aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler
diff options
context:
space:
mode:
authorGravatar Dan O'Reilly <oreilldf@gmail.com>2015-08-12 23:57:46 -0400
committerGravatar Dan O'Reilly <oreilldf@gmail.com>2015-08-12 23:57:46 -0400
commite47cdd5a559f488ba52756927ce68f4cf93874fa (patch)
tree8ce2723e822808baf58e96f569c86035717ea351 /src/google/protobuf/compiler
parentdaeaa6a28b81195f24d89222e649d79c9555af8b (diff)
parent38a56ee4b19d72c2e9d81a08b018704d1addf561 (diff)
Merge remote-tracking branch 'upstream/master' into py2_py3_straddle
Conflicts: python/google/protobuf/descriptor_pool.py python/google/protobuf/internal/api_implementation_default_test.py python/google/protobuf/internal/cpp_message.py python/google/protobuf/internal/descriptor_database_test.py python/google/protobuf/internal/descriptor_pool_test.py python/google/protobuf/internal/descriptor_python_test.py python/google/protobuf/internal/descriptor_test.py python/google/protobuf/internal/generator_test.py python/google/protobuf/internal/message_factory_python_test.py python/google/protobuf/internal/message_factory_test.py python/google/protobuf/internal/message_test.py python/google/protobuf/internal/proto_builder_test.py python/google/protobuf/internal/python_message.py python/google/protobuf/internal/reflection_test.py python/google/protobuf/internal/service_reflection_test.py python/google/protobuf/internal/symbol_database_test.py python/google/protobuf/internal/text_encoding_test.py python/google/protobuf/internal/text_format_test.py python/google/protobuf/internal/unknown_fields_test.py python/google/protobuf/internal/wire_format_test.py python/google/protobuf/pyext/descriptor_cpp2_test.py python/google/protobuf/pyext/message_factory_cpp2_test.py python/google/protobuf/pyext/reflection_cpp2_generated_test.py python/setup.py ruby/lib/google/protobuf/message_exts.rb
Diffstat (limited to 'src/google/protobuf/compiler')
-rw-r--r--src/google/protobuf/compiler/code_generator.h31
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc423
-rw-r--r--src/google/protobuf/compiler/command_line_interface.h12
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc109
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc32
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc127
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.h9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h28
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc553
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h29
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc76
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h28
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc147
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc759
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h29
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc303
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h17
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc66
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.h9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc169
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto18
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto43
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc52
-rw-r--r--src/google/protobuf/compiler/cpp/test_large_enum_value.proto43
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_enum.cc78
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_enum.h63
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_enum_field.cc119
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_enum_field.h77
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_field_base.cc425
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_field_base.h103
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_generator.cc100
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_generator.h58
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc54
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_helpers.cc393
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_helpers.h132
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_map_field.cc137
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_map_field.h71
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message.cc482
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message.h89
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message_field.cc193
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message_field.h86
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_names.h82
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_primitive_field.cc214
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_primitive_field.h88
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc125
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h73
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc140
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h71
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc123
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h71
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc66
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_source_generator_base.h64
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc295
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_umbrella_class.h70
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc207
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_wrapper_field.h85
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc16
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field_lite.cc967
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field_lite.h159
-rw-r--r--src/google/protobuf/compiler/java/java_extension.cc8
-rw-r--r--src/google/protobuf/compiler/java/java_extension.h12
-rw-r--r--src/google/protobuf/compiler/java/java_field.cc108
-rw-r--r--src/google/protobuf/compiler/java/java_field.h31
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc98
-rw-r--r--src/google/protobuf/compiler/java/java_generator_factory.cc8
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.cc4
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.h20
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field.cc236
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc708
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field_lite.h118
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.cc120
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.h3
-rw-r--r--src/google/protobuf/compiler/java/java_map_field_lite.cc459
-rw-r--r--src/google/protobuf/compiler/java/java_map_field_lite.h78
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc1102
-rw-r--r--src/google/protobuf/compiler/java/java_message.h21
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder.cc661
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder.h86
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder_lite.cc192
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder_lite.h83
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc410
-rw-r--r--src/google/protobuf/compiler/java/java_message_field_lite.cc944
-rw-r--r--src/google/protobuf/compiler/java/java_message_field_lite.h157
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.cc1174
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.h91
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc18
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field_lite.cc892
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field_lite.h163
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.cc2
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.cc4
-rw-r--r--src/google/protobuf/compiler/java/java_string_field_lite.cc1013
-rw-r--r--src/google/protobuf/compiler/java/java_string_field_lite.h158
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum.cc40
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.cc32
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.h1
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.cc2
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.cc68
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.h11
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc15
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.cc27
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.h10
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_map_field.cc186
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_map_field.h70
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc151
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.h2
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.cc110
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.h25
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_params.h20
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.cc106
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.h28
-rw-r--r--src/google/protobuf/compiler/main.cc12
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.cc8
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_enum.cc198
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_enum.h73
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc144
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_enum_field.h78
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_extension.cc136
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_extension.h69
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_field.cc434
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_field.h168
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.cc371
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.h97
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_generator.cc86
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_generator.h60
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.cc1045
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.h173
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc257
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_map_field.cc163
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_map_field.h64
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message.cc647
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message.h94
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message_field.cc96
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message_field.h74
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_oneof.cc138
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_oneof.h77
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc171
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h82
-rw-r--r--src/google/protobuf/compiler/parser.cc174
-rw-r--r--src/google/protobuf/compiler/parser.h45
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc335
-rw-r--r--src/google/protobuf/compiler/plugin.cc41
-rw-r--r--src/google/protobuf/compiler/plugin.pb.cc437
-rw-r--r--src/google/protobuf/compiler/plugin.pb.h159
-rw-r--r--src/google/protobuf/compiler/plugin.proto2
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc30
-rw-r--r--src/google/protobuf/compiler/python/python_generator.h3
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generated_code.proto67
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generated_code.rb74
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator.cc124
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator.h3
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc123
-rw-r--r--src/google/protobuf/compiler/subprocess.cc2
159 files changed, 23050 insertions, 2387 deletions
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index 321a8ccd..b989f151 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -79,6 +79,37 @@ class LIBPROTOC_EXPORT CodeGenerator {
GeneratorContext* generator_context,
string* error) const = 0;
+ // Generates code for all given proto files, generating one or more files in
+ // the given output directory.
+ //
+ // This method should be called instead of |Generate()| when
+ // |HasGenerateAll()| returns |true|. It is used to emulate legacy semantics
+ // when more than one `.proto` file is specified on one compiler invocation.
+ //
+ // WARNING: Please do not use unless legacy semantics force the code generator
+ // to produce a single output file for all input files, or otherwise require
+ // an examination of all input files first. The canonical code generator
+ // design produces one output file per input .proto file, and we do not wish
+ // to encourage alternate designs.
+ //
+ // A parameter is given as passed on the command line, as in |Generate()|
+ // above.
+ //
+ // Returns true if successful. Otherwise, sets *error to a description of
+ // the problem (e.g. "invalid parameter") and returns false.
+ virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const {
+ *error = "Unimplemented GenerateAll() method.";
+ return false;
+ }
+
+ // Returns true if the code generator expects to receive all FileDescriptors
+ // at once (via |GenerateAll()|), rather than one at a time (via
+ // |Generate()|). This is required to implement legacy semantics.
+ virtual bool HasGenerateAll() const { return false; }
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator);
};
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 13250702..e8871861 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -48,12 +48,15 @@
#include <iostream>
#include <ctype.h>
-#include <google/protobuf/stubs/hash.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif
+
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/compiler/importer.h>
@@ -152,7 +155,7 @@ bool VerifyDirectoryExists(const string& path) {
if (path.empty()) return true;
if (access(path.c_str(), F_OK) == -1) {
- cerr << path << ": " << strerror(errno) << endl;
+ std::cerr << path << ": " << strerror(errno) << std::endl;
return false;
} else {
return true;
@@ -171,8 +174,8 @@ bool TryCreateParentDirectory(const string& prefix, const string& filename) {
path_so_far += parts[i];
if (mkdir(path_so_far.c_str(), 0777) != 0) {
if (errno != EEXIST) {
- cerr << filename << ": while trying to create directory "
- << path_so_far << ": " << strerror(errno) << endl;
+ std::cerr << filename << ": while trying to create directory "
+ << path_so_far << ": " << strerror(errno) << std::endl;
return false;
}
}
@@ -182,6 +185,78 @@ bool TryCreateParentDirectory(const string& prefix, const string& filename) {
return true;
}
+// Get the absolute path of this protoc binary.
+bool GetProtocAbsolutePath(string* path) {
+#ifdef _WIN32
+ char buffer[MAX_PATH];
+ int len = GetModuleFileNameA(NULL, buffer, MAX_PATH);
+#elif __APPLE__
+ char buffer[PATH_MAX];
+ int len = 0;
+
+ char dirtybuffer[PATH_MAX];
+ uint32_t size = sizeof(dirtybuffer);
+ if (_NSGetExecutablePath(dirtybuffer, &size) == 0) {
+ realpath(dirtybuffer, buffer);
+ len = strlen(buffer);
+ }
+#else
+ char buffer[PATH_MAX];
+ int len = readlink("/proc/self/exe", buffer, PATH_MAX);
+#endif
+ if (len > 0) {
+ path->assign(buffer, len);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Whether a path is where google/protobuf/descriptor.proto and other well-known
+// type protos are installed.
+bool IsInstalledProtoPath(const string& path) {
+ // Checking the descriptor.proto file should be good enough.
+ string file_path = path + "/google/protobuf/descriptor.proto";
+ return access(file_path.c_str(), F_OK) != -1;
+}
+
+// Add the paths where google/protobuf/descritor.proto and other well-known
+// type protos are installed.
+void AddDefaultProtoPaths(vector<pair<string, string> >* paths) {
+ // TODO(xiaofeng): The code currently only checks relative paths of where
+ // the protoc binary is installed. We probably should make it handle more
+ // cases than that.
+ string path;
+ if (!GetProtocAbsolutePath(&path)) {
+ return;
+ }
+ // Strip the binary name.
+ size_t pos = path.find_last_of("/\\");
+ if (pos == string::npos || pos == 0) {
+ return;
+ }
+ path = path.substr(0, pos);
+ // Check the binary's directory.
+ if (IsInstalledProtoPath(path)) {
+ paths->push_back(pair<string, string>("", path));
+ return;
+ }
+ // Check if there is an include subdirectory.
+ if (IsInstalledProtoPath(path + "/include")) {
+ paths->push_back(pair<string, string>("", path + "/include"));
+ return;
+ }
+ // Check if the upper level directory has an "include" subdirectory.
+ pos = path.find_last_of("/\\");
+ if (pos == string::npos || pos == 0) {
+ return;
+ }
+ path = path.substr(0, pos);
+ if (IsInstalledProtoPath(path + "/include")) {
+ paths->push_back(pair<string, string>("", path + "/include"));
+ return;
+ }
+}
} // namespace
// A MultiFileErrorCollector that prints errors to stderr.
@@ -201,9 +276,9 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
tree_ != NULL &&
tree_->VirtualFileToDiskFile(filename, &dfile)) {
- cerr << dfile;
+ std::cerr << dfile;
} else {
- cerr << filename;
+ std::cerr << filename;
}
// Users typically expect 1-based line/column numbers, so we add 1
@@ -212,15 +287,16 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
// Allow for both GCC- and Visual-Studio-compatible output.
switch (format_) {
case CommandLineInterface::ERROR_FORMAT_GCC:
- cerr << ":" << (line + 1) << ":" << (column + 1);
+ std::cerr << ":" << (line + 1) << ":" << (column + 1);
break;
case CommandLineInterface::ERROR_FORMAT_MSVS:
- cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
+ std::cerr << "(" << (line + 1)
+ << ") : error in column=" << (column + 1);
break;
}
}
- cerr << ": " << message << endl;
+ std::cerr << ": " << message << std::endl;
}
// implements io::ErrorCollector -----------------------------------
@@ -254,6 +330,9 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
// format, unless one has already been written.
void AddJarManifest();
+ // Get name of all output files.
+ void GetOutputFilenames(vector<string>* output_filenames);
+
// implements GeneratorContext --------------------------------------
io::ZeroCopyOutputStream* Open(const string& filename);
io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
@@ -345,7 +424,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
if (file_descriptor < 0) {
int error = errno;
- cerr << filename << ": " << strerror(error);
+ std::cerr << filename << ": " << strerror(error);
return false;
}
@@ -369,9 +448,9 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
if (write_result < 0) {
int error = errno;
- cerr << filename << ": write: " << strerror(error);
+ std::cerr << filename << ": write: " << strerror(error);
} else {
- cerr << filename << ": write() returned zero?" << endl;
+ std::cerr << filename << ": write() returned zero?" << std::endl;
}
return false;
}
@@ -382,7 +461,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
if (close(file_descriptor) != 0) {
int error = errno;
- cerr << filename << ": close: " << strerror(error);
+ std::cerr << filename << ": close: " << strerror(error);
return false;
}
}
@@ -405,7 +484,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
if (file_descriptor < 0) {
int error = errno;
- cerr << filename << ": " << strerror(error);
+ std::cerr << filename << ": " << strerror(error);
return false;
}
@@ -421,11 +500,11 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
zip_writer.WriteDirectory();
if (stream.GetErrno() != 0) {
- cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+ std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
}
if (!stream.Close()) {
- cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+ std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
}
return true;
@@ -441,6 +520,14 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
}
}
+void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames(
+ vector<string>* output_filenames) {
+ for (map<string, string*>::iterator iter = files_.begin();
+ iter != files_.end(); ++iter) {
+ output_filenames->push_back(iter->first);
+ }
+}
+
io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
const string& filename) {
return new MemoryOutputStream(this, filename, false);
@@ -490,7 +577,8 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
if (append_mode_) {
(*map_slot)->append(data_);
} else {
- cerr << filename_ << ": Tried to write the same file twice." << endl;
+ std::cerr << filename_ << ": Tried to write the same file twice."
+ << std::endl;
directory_->had_error_ = true;
}
return;
@@ -508,8 +596,9 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
// Find the file we are going to insert into.
if (*map_slot == NULL) {
- cerr << filename_ << ": Tried to insert into file that doesn't exist."
- << endl;
+ std::cerr << filename_
+ << ": Tried to insert into file that doesn't exist."
+ << std::endl;
directory_->had_error_ = true;
return;
}
@@ -521,8 +610,8 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
string::size_type pos = target->find(magic_string);
if (pos == string::npos) {
- cerr << filename_ << ": insertion point \"" << insertion_point_
- << "\" not found." << endl;
+ std::cerr << filename_ << ": insertion point \"" << insertion_point_
+ << "\" not found." << std::endl;
directory_->had_error_ = true;
return;
}
@@ -631,6 +720,8 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
break;
}
+ AddDefaultProtoPaths(&proto_path_);
+
// Set up the source tree.
DiskSourceTree source_tree;
for (int i = 0; i < proto_path_.size(); i++) {
@@ -670,7 +761,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// We construct a separate GeneratorContext for each output location. Note
// that two code generators may output to the same location, in which case
// they should share a single GeneratorContext so that OpenForInsert() works.
- typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
GeneratorContextMap output_directories;
// Generate output.
@@ -717,6 +807,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
+ if (!dependency_out_name_.empty()) {
+ if (!GenerateDependencyManifestFile(parsed_files, output_directories,
+ &source_tree)) {
+ return 1;
+ }
+ }
+
STLDeleteValues(&output_directories);
if (!descriptor_set_name_.empty()) {
@@ -775,6 +872,7 @@ void CommandLineInterface::Clear() {
output_directives_.clear();
codec_type_.clear();
descriptor_set_name_.clear();
+ dependency_out_name_.clear();
mode_ = MODE_COMPILE;
print_mode_ = PRINT_NONE;
@@ -793,27 +891,31 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
input_files_[i] = virtual_file;
break;
case DiskSourceTree::SHADOWED:
- cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
- "by \"" << shadowing_disk_file << "\". Either use the latter "
- "file as your input or reorder the --proto_path so that the "
- "former file's location comes first." << endl;
+ std::cerr << input_files_[i]
+ << ": Input is shadowed in the --proto_path by \""
+ << shadowing_disk_file
+ << "\". Either use the latter file as your input or reorder "
+ "the --proto_path so that the former file's location "
+ "comes first." << std::endl;
return false;
case DiskSourceTree::CANNOT_OPEN:
- cerr << input_files_[i] << ": " << strerror(errno) << endl;
+ std::cerr << input_files_[i] << ": " << strerror(errno) << std::endl;
return false;
case DiskSourceTree::NO_MAPPING:
// First check if the file exists at all.
if (access(input_files_[i].c_str(), F_OK) < 0) {
// File does not even exist.
- cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
+ std::cerr << input_files_[i] << ": " << strerror(ENOENT) << std::endl;
} else {
- cerr << input_files_[i] << ": File does not reside within any path "
- "specified using --proto_path (or -I). You must specify a "
- "--proto_path which encompasses this file. Note that the "
- "proto_path must be an exact prefix of the .proto file "
- "names -- protoc is too dumb to figure out when two paths "
- "(e.g. absolute and relative) are equivalent (it's harder "
- "than you think)." << endl;
+ std::cerr
+ << input_files_[i]
+ << ": File does not reside within any path "
+ "specified using --proto_path (or -I). You must specify a "
+ "--proto_path which encompasses this file. Note that the "
+ "proto_path must be an exact prefix of the .proto file "
+ "names -- protoc is too dumb to figure out when two paths "
+ "(e.g. absolute and relative) are equivalent (it's harder "
+ "than you think)." << std::endl;
}
return false;
}
@@ -833,9 +935,10 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
if (ParseArgument(argv[i], &name, &value)) {
// Returned true => Use the next argument as the flag value.
if (i + 1 == argc || argv[i+1][0] == '-') {
- cerr << "Missing value for flag: " << name << endl;
+ std::cerr << "Missing value for flag: " << name << std::endl;
if (name == "--decode") {
- cerr << "To decode an unknown message, use --decode_raw." << endl;
+ std::cerr << "To decode an unknown message, use --decode_raw."
+ << std::endl;
}
return PARSE_ARGUMENT_FAIL;
} else {
@@ -860,24 +963,36 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
// 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;
+ std::cerr << "When using --decode_raw, no input files should be given."
+ << std::endl;
return PARSE_ARGUMENT_FAIL;
} else if (!decoding_raw && input_files_.empty()) {
- cerr << "Missing input file." << endl;
+ std::cerr << "Missing input file." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
if (mode_ == MODE_COMPILE && output_directives_.empty() &&
descriptor_set_name_.empty()) {
- cerr << "Missing output directives." << endl;
+ std::cerr << "Missing output directives." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) {
+ std::cerr << "Can only use --dependency_out=FILE when generating code."
+ << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (!dependency_out_name_.empty() && input_files_.size() > 1) {
+ std::cerr
+ << "Can only process one input file when using --dependency_out=FILE."
+ << std::endl;
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;
+ std::cerr << "--include_imports only makes sense when combined with "
+ "--descriptor_set_out." << std::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;
+ std::cerr << "--include_source_info only makes sense when combined with "
+ "--descriptor_set_out." << std::endl;
}
return PARSE_ARGUMENT_DONE_AND_CONTINUE;
@@ -950,10 +1065,12 @@ CommandLineInterface::InterpretArgument(const string& name,
if (name.empty()) {
// Not a flag. Just a filename.
if (value.empty()) {
- cerr << "You seem to have passed an empty string as one of the "
- "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;
+ std::cerr
+ << "You seem to have passed an empty string as one of the "
+ "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." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
@@ -980,14 +1097,16 @@ CommandLineInterface::InterpretArgument(const string& name,
}
if (disk_path.empty()) {
- cerr << "--proto_path passed empty directory name. (Use \".\" for "
- "current directory.)" << endl;
+ std::cerr
+ << "--proto_path passed empty directory name. (Use \".\" for "
+ "current directory.)" << std::endl;
return PARSE_ARGUMENT_FAIL;
}
// Make sure disk path exists, warn otherwise.
if (access(disk_path.c_str(), F_OK) < 0) {
- cerr << disk_path << ": warning: directory does not exist." << endl;
+ std::cerr << disk_path << ": warning: directory does not exist."
+ << std::endl;
}
// Don't use make_pair as the old/default standard library on Solaris
@@ -998,30 +1117,42 @@ CommandLineInterface::InterpretArgument(const string& name,
} else if (name == "-o" || name == "--descriptor_set_out") {
if (!descriptor_set_name_.empty()) {
- cerr << name << " may only be passed once." << endl;
+ std::cerr << name << " may only be passed once." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
if (value.empty()) {
- cerr << name << " requires a non-empty value." << endl;
+ std::cerr << name << " requires a non-empty value." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode or --decode and generate descriptors at the "
- "same time." << endl;
+ std::cerr
+ << "Cannot use --encode or --decode and generate descriptors at the "
+ "same time." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
descriptor_set_name_ = value;
+ } else if (name == "--dependency_out") {
+ if (!dependency_out_name_.empty()) {
+ std::cerr << name << " may only be passed once." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (value.empty()) {
+ std::cerr << name << " requires a non-empty value." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ dependency_out_name_ = value;
+
} else if (name == "--include_imports") {
if (imports_in_descriptor_set_) {
- cerr << name << " may only be passed once." << endl;
+ std::cerr << name << " may only be passed once." << std::endl;
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;
+ std::cerr << name << " may only be passed once." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
source_info_in_descriptor_set_ = true;
@@ -1032,7 +1163,7 @@ CommandLineInterface::InterpretArgument(const string& name,
} else if (name == "--version") {
if (!version_info_.empty()) {
- cout << version_info_ << endl;
+ std::cout << version_info_ << std::endl;
}
cout << "libprotoc "
<< protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
@@ -1045,25 +1176,28 @@ CommandLineInterface::InterpretArgument(const string& name,
} else if (name == "--encode" || name == "--decode" ||
name == "--decode_raw") {
if (mode_ != MODE_COMPILE) {
- cerr << "Only one of --encode and --decode can be specified." << endl;
+ std::cerr << "Only one of --encode and --decode can be specified."
+ << std::endl;
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;
+ std::cerr << "Cannot use " << name
+ << " and generate code or descriptors at the same time."
+ << std::endl;
return PARSE_ARGUMENT_FAIL;
}
mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
if (value.empty() && name != "--decode_raw") {
- cerr << "Type name for " << name << " cannot be blank." << endl;
+ std::cerr << "Type name for " << name << " cannot be blank." << std::endl;
if (name == "--decode") {
- cerr << "To decode an unknown message, use --decode_raw." << endl;
+ std::cerr << "To decode an unknown message, use --decode_raw."
+ << std::endl;
}
return PARSE_ARGUMENT_FAIL;
} else if (!value.empty() && name == "--decode_raw") {
- cerr << "--decode_raw does not take a parameter." << endl;
+ std::cerr << "--decode_raw does not take a parameter." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
@@ -1075,13 +1209,13 @@ CommandLineInterface::InterpretArgument(const string& name,
} else if (value == "msvs") {
error_format_ = ERROR_FORMAT_MSVS;
} else {
- cerr << "Unknown error format: " << value << endl;
+ std::cerr << "Unknown error format: " << value << std::endl;
return PARSE_ARGUMENT_FAIL;
}
} else if (name == "--plugin") {
if (plugin_prefix_.empty()) {
- cerr << "This compiler does not support plugins." << endl;
+ std::cerr << "This compiler does not support plugins." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
@@ -1107,13 +1241,15 @@ CommandLineInterface::InterpretArgument(const string& name,
} else if (name == "--print_free_field_numbers") {
if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use " << name << " and use --encode, --decode or print "
- << "other info at the same time." << endl;
+ std::cerr << "Cannot use " << name
+ << " and use --encode, --decode or print "
+ << "other info at the same time." << std::endl;
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;
+ std::cerr << "Cannot use " << name
+ << " and generate code or descriptors at the same time."
+ << std::endl;
return PARSE_ARGUMENT_FAIL;
}
mode_ = MODE_PRINT;
@@ -1127,7 +1263,7 @@ CommandLineInterface::InterpretArgument(const string& name,
// 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;
+ std::cerr << "Unknown flag: " << name << std::endl;
return PARSE_ARGUMENT_FAIL;
} else {
string* parameters = &generator_parameters_[generator_info->flag_name];
@@ -1139,8 +1275,8 @@ CommandLineInterface::InterpretArgument(const string& name,
} else {
// It's an output flag. Add it to the output directives.
if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode, --decode or print .proto info and "
- "generate code at the same time." << endl;
+ std::cerr << "Cannot use --encode, --decode or print .proto info and "
+ "generate code at the same time." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
@@ -1172,7 +1308,7 @@ CommandLineInterface::InterpretArgument(const string& name,
void CommandLineInterface::PrintHelpText() {
// Sorry for indentation here; line wrapping would be uglier.
- cerr <<
+ std::cerr <<
"Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
"Parse PROTO_FILES and generate output based on the options given:\n"
" -IPATH, --proto_path=PATH Specify the directory in which to search for\n"
@@ -1206,6 +1342,9 @@ void CommandLineInterface::PrintHelpText() {
" include information about the original\n"
" location of each decl in the source file as\n"
" well as surrounding comments.\n"
+" --dependency_out=FILE Write a dependency output file in the format\n"
+" expected by make. This writes the transitive\n"
+" set of input file paths to FILE\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).\n"
@@ -1213,9 +1352,10 @@ void CommandLineInterface::PrintHelpText() {
" defined in the given proto files. Groups share\n"
" the same field number space with the parent \n"
" message. Extension ranges are counted as \n"
-" occupied fields numbers." << endl;
+" occupied fields numbers."
+ << std::endl;
if (!plugin_prefix_.empty()) {
- cerr <<
+ std::cerr <<
" --plugin=EXECUTABLE Specifies a plugin executable to use.\n"
" Normally, protoc searches the PATH for\n"
" plugins, but you may specify additional\n"
@@ -1223,7 +1363,7 @@ void CommandLineInterface::PrintHelpText() {
" Additionally, EXECUTABLE may be of the form\n"
" NAME=PATH, in which case the given plugin name\n"
" is mapped to the given executable even if\n"
-" the executable's own name differs." << endl;
+" the executable's own name differs." << std::endl;
}
for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
@@ -1231,9 +1371,9 @@ void CommandLineInterface::PrintHelpText() {
// 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.
- cerr << " " << iter->first << "=OUT_DIR "
- << string(19 - iter->first.size(), ' ') // Spaces for alignment.
- << iter->second.help_text << endl;
+ std::cerr << " " << iter->first << "=OUT_DIR "
+ << string(19 - iter->first.size(), ' ') // Spaces for alignment.
+ << iter->second.help_text << std::endl;
}
}
@@ -1256,7 +1396,7 @@ bool CommandLineInterface::GenerateOutput(
if (!GeneratePluginOutput(parsed_files, plugin_name,
output_directive.parameter,
generator_context, &error)) {
- cerr << output_directive.name << ": " << error << endl;
+ std::cerr << output_directive.name << ": " << error << std::endl;
return false;
}
} else {
@@ -1268,14 +1408,95 @@ bool CommandLineInterface::GenerateOutput(
}
parameters.append(generator_parameters_[output_directive.name]);
}
- for (int i = 0; i < parsed_files.size(); i++) {
- 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;
- return false;
+ if (output_directive.generator->HasGenerateAll()) {
+ if (!output_directive.generator->GenerateAll(
+ parsed_files, parameters, generator_context, &error)) {
+ // Generator returned an error.
+ std::cerr << output_directive.name << ": "
+ << ": " << error << std::endl;
+ return false;
+ }
+ } else {
+ for (int i = 0; i < parsed_files.size(); i++) {
+ if (!output_directive.generator->Generate(parsed_files[i], parameters,
+ generator_context, &error)) {
+ // Generator returned an error.
+ std::cerr << output_directive.name << ": " << parsed_files[i]->name()
+ << ": " << error << std::endl;
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool CommandLineInterface::GenerateDependencyManifestFile(
+ const vector<const FileDescriptor*>& parsed_files,
+ const GeneratorContextMap& output_directories,
+ DiskSourceTree* source_tree) {
+ FileDescriptorSet file_set;
+
+ set<const FileDescriptor*> already_seen;
+ for (int i = 0; i < parsed_files.size(); i++) {
+ GetTransitiveDependencies(parsed_files[i],
+ false,
+ &already_seen,
+ file_set.mutable_file());
+ }
+
+ vector<string> output_filenames;
+ for (GeneratorContextMap::const_iterator iter = output_directories.begin();
+ iter != output_directories.end(); ++iter) {
+ const string& location = iter->first;
+ GeneratorContextImpl* directory = iter->second;
+ vector<string> relative_output_filenames;
+ directory->GetOutputFilenames(&relative_output_filenames);
+ for (int i = 0; i < relative_output_filenames.size(); i++) {
+ string output_filename = location + relative_output_filenames[i];
+ if (output_filename.compare(0, 2, "./") == 0) {
+ output_filename = output_filename.substr(2);
}
+ output_filenames.push_back(output_filename);
+ }
+ }
+
+ int fd;
+ do {
+ fd = open(dependency_out_name_.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ } while (fd < 0 && errno == EINTR);
+
+ if (fd < 0) {
+ perror(dependency_out_name_.c_str());
+ return false;
+ }
+
+ io::FileOutputStream out(fd);
+ io::Printer printer(&out, '$');
+
+ for (int i = 0; i < output_filenames.size(); i++) {
+ printer.Print(output_filenames[i].c_str());
+ if (i == output_filenames.size() - 1) {
+ printer.Print(":");
+ } else {
+ printer.Print(" \\\n");
+ }
+ }
+
+ for (int i = 0; i < file_set.file_size(); i++) {
+ const FileDescriptorProto& file = file_set.file(i);
+ const string& virtual_file = file.name();
+ string disk_file;
+ if (source_tree &&
+ source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) {
+ printer.Print(" $disk_file$", "disk_file", disk_file);
+ if (i < file_set.file_size() - 1) printer.Print("\\\n");
+ } else {
+ std::cerr << "Unable to identify path for file " << virtual_file
+ << std::endl;
+ return false;
}
}
@@ -1365,7 +1586,7 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
// Look up the type.
const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
if (type == NULL) {
- cerr << "Type not defined: " << codec_type_ << endl;
+ std::cerr << "Type not defined: " << codec_type_ << std::endl;
return false;
}
@@ -1391,32 +1612,32 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
parser.AllowPartialMessage(true);
if (!parser.Parse(&in, message.get())) {
- cerr << "Failed to parse input." << endl;
+ std::cerr << "Failed to parse input." << std::endl;
return false;
}
} else {
// Input is binary.
if (!message->ParsePartialFromZeroCopyStream(&in)) {
- cerr << "Failed to parse input." << endl;
+ std::cerr << "Failed to parse input." << std::endl;
return false;
}
}
if (!message->IsInitialized()) {
- cerr << "warning: Input message is missing required fields: "
- << message->InitializationErrorString() << endl;
+ std::cerr << "warning: Input message is missing required fields: "
+ << message->InitializationErrorString() << std::endl;
}
if (mode_ == MODE_ENCODE) {
// Output is binary.
if (!message->SerializePartialToZeroCopyStream(&out)) {
- cerr << "output: I/O error." << endl;
+ std::cerr << "output: I/O error." << std::endl;
return false;
}
} else {
// Output is text.
if (!TextFormat::Print(*message, &out)) {
- cerr << "output: I/O error." << endl;
+ std::cerr << "output: I/O error." << std::endl;
return false;
}
}
@@ -1458,12 +1679,14 @@ bool CommandLineInterface::WriteDescriptorSet(
io::FileOutputStream out(fd);
if (!file_set.SerializeToZeroCopyStream(&out)) {
- cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+ std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+ << std::endl;
out.Close();
return false;
}
if (!out.Close()) {
- cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+ std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+ << std::endl;
return false;
}
@@ -1542,6 +1765,10 @@ void GatherOccupiedFieldRanges(const Descriptor* descriptor,
ranges->insert(FieldRange(descriptor->extension_range(i)->start,
descriptor->extension_range(i)->end));
}
+ for (int i = 0; i < descriptor->reserved_range_count(); ++i) {
+ ranges->insert(FieldRange(descriptor->reserved_range(i)->start,
+ descriptor->reserved_range(i)->end));
+ }
// Handle the nested messages/groups in declaration order to make it
// post-order strict.
for (int i = 0; i < descriptor->nested_type_count(); ++i) {
@@ -1582,7 +1809,7 @@ void FormatFreeFieldNumbers(const string& name,
if (next_free_number <= FieldDescriptor::kMaxNumber) {
StringAppendF(&output, " %d-INF", next_free_number);
}
- cout << output << endl;
+ std::cout << output << std::endl;
}
} // namespace
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 74a0adb4..7e611c44 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -39,6 +39,7 @@
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
#include <string>
#include <vector>
#include <map>
@@ -190,6 +191,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
class ErrorPrinter;
class GeneratorContextImpl;
class MemoryOutputStream;
+ typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
// Clear state from previous Run().
void Clear();
@@ -247,6 +249,12 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Implements the --descriptor_set_out option.
bool WriteDescriptorSet(const vector<const FileDescriptor*> parsed_files);
+ // Implements the --dependency_out option
+ bool GenerateDependencyManifestFile(
+ const vector<const FileDescriptor*>& parsed_files,
+ const GeneratorContextMap& output_directories,
+ DiskSourceTree* source_tree);
+
// Get all transitive dependencies of the given file (including the file
// itself), adding them to the given list of FileDescriptorProtos. The
// protos will be ordered such that every file is listed before any file that
@@ -353,6 +361,10 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// FileDescriptorSet should be written. Otherwise, empty.
string descriptor_set_name_;
+ // If --dependency_out was given, this is the path to the file where the
+ // dependency file will be written. Otherwise, empty.
+ string dependency_out_name_;
+
// True if --include_imports was given, meaning that we should
// write all transitive dependencies to the DescriptorSet. Otherwise, only
// the .proto files listed on the command-line are added.
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index dbaaa405..e5b77c33 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -64,6 +64,9 @@
#include <gtest/gtest.h>
+// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
+// which case tcmalloc will print warnings that fail the plugin tests.
+#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
namespace google {
namespace protobuf {
namespace compiler {
@@ -112,6 +115,16 @@ class CommandLineInterfaceTest : public testing::Test {
// Create a subdirectory within temp_directory_.
void CreateTempDir(const string& name);
+#ifdef PROTOBUF_OPENSOURCE
+ // Change working directory to temp directory.
+ void SwitchToTempDirectory() {
+ File::ChangeWorkingDirectory(temp_directory_);
+ }
+#else // !PROTOBUF_OPENSOURCE
+ // TODO(teboring): Figure out how to change and get working directory in
+ // google3.
+#endif // !PROTOBUF_OPENSOURCE
+
void SetInputsAreProtoPathRelative(bool enable) {
cli_.SetInputsAreProtoPathRelative(enable);
}
@@ -176,6 +189,9 @@ class CommandLineInterfaceTest : public testing::Test {
void ReadDescriptorSet(const string& filename,
FileDescriptorSet* descriptor_set);
+ void ExpectFileContent(const string& filename,
+ const string& content);
+
private:
// The object we are testing.
CommandLineInterface cli_;
@@ -277,6 +293,7 @@ void CommandLineInterfaceTest::Run(const string& command) {
if (!disallow_plugins_) {
cli_.AllowPlugins("prefix-");
+#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
const char* possible_paths[] = {
// When building with shared libraries, libtool hides the real executable
// in .libs and puts a fake wrapper in the current directory.
@@ -305,6 +322,11 @@ void CommandLineInterfaceTest::Run(const string& command) {
}
if (plugin_path.empty()) {
+#else
+ string plugin_path = "third_party/protobuf/test_plugin";
+
+ if (access(plugin_path.c_str(), F_OK) != 0) {
+#endif // GOOGLE_THIRD_PARTY_PROTOBUF
GOOGLE_LOG(ERROR)
<< "Plugin executable not found. Plugin tests are likely to fail.";
} else {
@@ -456,6 +478,17 @@ void CommandLineInterfaceTest::ExpectCapturedStdout(
EXPECT_EQ(expected_text, captured_stdout_);
}
+
+void CommandLineInterfaceTest::ExpectFileContent(
+ const string& filename, const string& content) {
+ string path = temp_directory_ + "/" + filename;
+ string file_contents;
+ GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
+
+ EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true),
+ file_contents);
+}
+
// ===================================================================
TEST_F(CommandLineInterfaceTest, BasicOutput) {
@@ -940,6 +973,80 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
}
+#ifdef _WIN32
+// TODO(teboring): Figure out how to write test on windows.
+#else
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) {
+ 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 --dependency_out=$tmpdir/manifest "
+ "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto");
+
+ ExpectErrorText(
+ "Can only process one input file when using --dependency_out=FILE.\n");
+}
+
+#ifdef PROTOBUF_OPENSOURCE
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
+ 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");
+
+ string current_working_directory = getcwd(NULL, 0);
+ SwitchToTempDirectory();
+
+ Run("protocol_compiler --dependency_out=manifest --test_out=. "
+ "bar.proto");
+
+ ExpectNoErrors();
+
+ ExpectFileContent("manifest",
+ "bar.proto.MockCodeGenerator.test_generator: "
+ "foo.proto\\\n bar.proto");
+
+ File::ChangeWorkingDirectory(current_working_directory);
+}
+#else // !PROTOBUF_OPENSOURCE
+// TODO(teboring): Figure out how to change and get working directory in
+// google3.
+#endif // !PROTOBUF_OPENSOURCE
+
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) {
+ 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 --dependency_out=$tmpdir/manifest "
+ "--test_out=$tmpdir --proto_path=$tmpdir bar.proto");
+
+ ExpectNoErrors();
+
+ ExpectFileContent("manifest",
+ "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
+ "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
+}
+#endif // !_WIN32
+
// -------------------------------------------------------------------
TEST_F(CommandLineInterfaceTest, ParseErrors) {
@@ -1662,4 +1769,6 @@ TEST_F(EncodeDecodeTest, ProtoParseError) {
} // namespace compiler
} // namespace protobuf
+
+#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index 48788197..13ed0b64 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -98,7 +98,8 @@ class MockGeneratorContext : public GeneratorContext {
&actual_contents, true));
EXPECT_TRUE(actual_contents == *expected_contents)
<< physical_filename << " needs to be regenerated. Please run "
- "generate_descriptor_proto.sh and add this file "
+ "google/protobuf/compiler/release_compiler.sh and "
+ "generate_descriptor_proto.sh. Then add this file "
"to your CL.";
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 3ce1f120..70d3a600 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -47,7 +47,7 @@ namespace cpp {
namespace {
// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
-// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
// generation of the GOOGLE_ARRAYSIZE constant.
bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
int32 max_value = descriptor->value(0)->number();
@@ -56,7 +56,7 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
max_value = descriptor->value(i)->number();
}
}
- return max_value != kint32max;
+ return max_value != ::google::protobuf::kint32max;
}
} // namespace
@@ -70,19 +70,30 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
EnumGenerator::~EnumGenerator() {}
+void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) {
+ if (!options_.proto_h) {
+ return;
+ }
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ printer->Print(vars, "enum $classname$ : int;\n");
+ printer->Print(vars, "bool $classname$_IsValid(int value);\n");
+}
+
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = classname_;
vars["short_name"] = descriptor_->name();
+ vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
- printer->Print(vars, "enum $classname$ {\n");
+ printer->Print(vars, "enum $enumbase$ {\n");
printer->Indent();
const EnumValueDescriptor* min_value = descriptor_->value(0);
const EnumValueDescriptor* max_value = descriptor_->value(0);
for (int i = 0; i < descriptor_->value_count(); i++) {
- vars["name"] = descriptor_->value(i)->name();
+ vars["name"] = EnumValueName(descriptor_->value(i));
// In C++, an value of -2147483648 gets interpreted as the negative of
// 2147483648, and since 2147483648 can't fit in an integer, this produces a
// compiler warning. This works around that issue.
@@ -113,8 +124,8 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
printer->Outdent();
printer->Print("\n};\n");
- vars["min_name"] = min_value->name();
- vars["max_name"] = max_value->name();
+ vars["min_name"] = EnumValueName(min_value);
+ vars["max_name"] = EnumValueName(max_value);
if (options_.dllexport_decl.empty()) {
vars["dllexport"] = "";
@@ -153,9 +164,12 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
void EnumGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
+ printer->Print(
+ "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
+ "{};\n",
+ "classname", ClassName(descriptor_, true));
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
- "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type {};\n"
"template <>\n"
"inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
" return $classname$_descriptor();\n"
@@ -171,7 +185,7 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
printer->Print(vars, "typedef $classname$ $nested_name$;\n");
for (int j = 0; j < descriptor_->value_count(); j++) {
- vars["tag"] = descriptor_->value(j)->name();
+ vars["tag"] = EnumValueName(descriptor_->value(j));
printer->Print(vars,
"static const $nested_name$ $tag$ = $classname$_$tag$;\n");
}
@@ -275,7 +289,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
vars["parent"] = ClassName(descriptor_->containing_type(), false);
vars["nested_name"] = descriptor_->name();
for (int i = 0; i < descriptor_->value_count(); i++) {
- vars["value"] = descriptor_->value(i)->name();
+ vars["value"] = EnumValueName(descriptor_->value(i));
printer->Print(vars,
"const $classname$ $parent$::$value$;\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 1ebd7cf7..3e930856 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -60,6 +60,12 @@ class EnumGenerator {
// Header stuff.
+ // Generate header code to forward-declare the enum. This is for use when
+ // generating other .proto.h files. This code should be placed within the
+ // enum's package namespace, but NOT within any class, even for nested
+ // enums.
+ void GenerateForwardDeclaration(io::Printer* printer);
+
// Generate header code defining the enum. This code should be placed
// within the enum's package namespace, but NOT within any class, even for
// nested enums.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 17926135..965327b1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -76,23 +76,26 @@ GeneratePrivateMembers(io::Printer* printer) const {
void EnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$() const$deprecation$;\n"
- "inline void set_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$() const$deprecation$;\n"
+ "void set_$name$($type$ value)$deprecation$;\n");
}
void EnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_);\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n");
+ "$inline$ void $classname$::set_$name$($type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
- printer->Print(variables_,
+ printer->Print(variables,
" assert($type$_IsValid(value));\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" $set_hasbit$\n"
" $name$_ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
@@ -181,21 +184,24 @@ EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
void EnumOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return static_cast< $type$ >($oneof_prefix$$name$_);\n"
" }\n"
" return static_cast< $type$ >($default$);\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n");
+ "$inline$ void $classname$::set_$name$($type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
- printer->Print(variables_,
+ printer->Print(variables,
" assert($type$_IsValid(value));\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -236,7 +242,7 @@ void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField<int> $name$_;\n");
- if (descriptor_->options().packed()
+ if (descriptor_->is_packed()
&& HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
@@ -246,46 +252,49 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$(int index) const$deprecation$;\n"
- "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
- "inline void add_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$(int index) const$deprecation$;\n"
+ "void set_$name$(int index, $type$ value)$deprecation$;\n"
+ "void add_$name$($type$ value)$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
- "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
+ "const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
+ "::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
}
void RepeatedEnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_.Get(index));\n"
"}\n"
- "inline void $classname$::set_$name$(int index, $type$ value) {\n");
+ "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
- printer->Print(variables_,
+ printer->Print(variables,
" assert($type$_IsValid(value));\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" $name$_.Set(index, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::add_$name$($type$ value) {\n");
+ "$inline$ void $classname$::add_$name$($type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
- printer->Print(variables_,
+ printer->Print(variables,
" assert($type$_IsValid(value));\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField<int>&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedField<int>&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedField<int>*\n"
+ "$inline$ ::google::protobuf::RepeatedField<int>*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
@@ -343,21 +352,35 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
- if (!descriptor_->options().packed()) {
- // We use a non-inlined implementation in this case, since this path will
- // rarely be executed.
- printer->Print(variables_,
- "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
- " input,\n");
+ if (!descriptor_->is_packed()) {
+ // This path is rarely executed, so we use a non-inlined implementation.
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
- " NULL,\n");
+ "DO_((::google::protobuf::internal::"
+ "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+ " input,\n"
+ " $number$,\n"
+ " NULL,\n"
+ " NULL,\n"
+ " this->mutable_$name$())));\n");
+ } else if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(variables_,
+ "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n"
+ " input,\n"
+ " $number$,\n"
+ " $type$_IsValid,\n"
+ " mutable_unknown_fields(),\n"
+ " this->mutable_$name$())));\n");
} else {
printer->Print(variables_,
- " &$type$_IsValid,\n");
+ "DO_((::google::protobuf::internal::"
+ "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+ " input,\n"
+ " $number$,\n"
+ " $type$_IsValid,\n"
+ " &unknown_fields_stream,\n"
+ " this->mutable_$name$())));\n");
}
- printer->Print(variables_,
- " this->mutable_$name$())));\n");
} else {
printer->Print(variables_,
"::google::protobuf::uint32 length;\n"
@@ -376,6 +399,16 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
printer->Print(variables_,
" if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n"
+ " } else {\n");
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(variables_,
+ " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ } else {
+ printer->Print(variables_,
+ " unknown_fields_stream.WriteVarint32(tag);\n"
+ " unknown_fields_stream.WriteVarint32(value);\n");
+ }
+ printer->Print(
" }\n");
}
printer->Print(variables_,
@@ -386,7 +419,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -399,7 +432,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
" this->$name$(i), output);\n");
@@ -413,7 +446,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -427,7 +460,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
" this->$name$(i), target);\n");
@@ -451,7 +484,7 @@ GenerateByteSize(io::Printer* printer) const {
" this->$name$(i));\n"
"}\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index def2b232..5b1d01ea 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -53,7 +53,8 @@ class EnumFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
@@ -78,7 +79,8 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator {
~EnumOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
@@ -96,7 +98,8 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index c37fe0be..1d7f8233 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -82,14 +82,40 @@ class FieldGenerator {
// implementation is empty.
virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
+ // Generate prototypes for accessors that will manipulate imported
+ // messages inline. These are for .proto.h headers.
+ //
+ // In .proto.h mode, the headers of imports are not #included. However,
+ // functions that manipulate the imported message types need access to
+ // the class definition of the imported message, meaning that the headers
+ // must be #included. To get around this, functions that manipulate
+ // imported message objects are defined as dependent functions in a base
+ // template class. By making them dependent template functions, the
+ // function templates will not be instantiated until they are called, so
+ // we can defer to those translation units to #include the necessary
+ // generated headers.
+ //
+ // See:
+ // http://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
+ //
+ // Most field types don't need this, so the default implementation is empty.
+ virtual void GenerateDependentAccessorDeclarations(
+ io::Printer* printer) const {}
+
// Generate prototypes for all of the accessor functions related to this
// field. These are placed inside the class definition.
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
+ // Generate inline definitions of depenent accessor functions for this field.
+ // These are placed inside the header after all class definitions.
+ virtual void GenerateDependentInlineAccessorDefinitions(
+ io::Printer* printer) const {}
+
// Generate inline definitions of accessor functions for this field.
// These are placed inside the header after all class definitions.
+ // In non-.proto.h mode, this generates dependent accessor functions as well.
virtual void GenerateInlineAccessorDefinitions(
- io::Printer* printer) const = 0;
+ io::Printer* printer, bool is_inline) const = 0;
// Generate definitions of accessors that aren't inlined. These are
// placed somewhere in the .cc file.
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index fae4df40..1f0a8205 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -94,99 +94,10 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
FileGenerator::~FileGenerator() {}
void FileGenerator::GenerateHeader(io::Printer* printer) {
- string filename_identifier = FilenameIdentifier(file_->name());
-
- // Generate top of header.
- printer->Print(
- "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "// source: $filename$\n"
- "\n"
- "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
- "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
- "\n"
- "#include <string>\n"
- "\n",
- "filename", file_->name(),
- "filename_identifier", filename_identifier);
-
-
- printer->Print(
- "#include <google/protobuf/stubs/common.h>\n"
- "\n");
-
- // Verify the protobuf library header version is compatible with the protoc
- // version before going any further.
- printer->Print(
- "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
- "#error This file was generated by a newer version of protoc which is\n"
- "#error incompatible with your Protocol Buffer headers. Please update\n"
- "#error your headers.\n"
- "#endif\n"
- "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
- "#error This file was generated by an older version of protoc which is\n"
- "#error incompatible with your Protocol Buffer headers. Please\n"
- "#error regenerate this file with a newer version of protoc.\n"
- "#endif\n"
- "\n",
- "min_header_version",
- SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
- "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
-
- // OK, it's now safe to #include other files.
- printer->Print(
- "#include <google/protobuf/arena.h>\n"
- "#include <google/protobuf/arenastring.h>\n"
- "#include <google/protobuf/generated_message_util.h>\n"
- "#include <google/protobuf/metadata.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 (HasMapFields(file_)) {
- printer->Print(
- "#include <google/protobuf/map.h>\n"
- "#include <google/protobuf/map_field_inl.h>\n");
- }
-
- if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) {
- printer->Print(
- "#include <google/protobuf/generated_enum_reflection.h>\n");
- }
-
- if (HasGenericServices(file_)) {
- printer->Print(
- "#include <google/protobuf/service.h>\n");
- }
-
- if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
- printer->Print(
- "#include <google/protobuf/unknown_field_set.h>\n");
- }
-
-
- set<string> public_import_names;
- for (int i = 0; i < file_->public_dependency_count(); i++) {
- public_import_names.insert(file_->public_dependency(i)->name());
- }
-
- for (int i = 0; i < file_->dependency_count(); i++) {
- const string& name = file_->dependency(i)->name();
- bool public_import = (public_import_names.count(name) != 0);
+ GenerateTopHeaderGuard(printer);
-
- printer->Print(
- "#include \"$dependency$.pb.h\"$iwyu$\n",
- "dependency", StripProto(name),
- "iwyu", (public_import) ? " // IWYU pragma: export" : "");
- }
+ GenerateLibraryIncludes(printer);
+ GenerateDependencyIncludes(printer);
printer->Print(
"// @@protoc_insertion_point(includes)\n");
@@ -196,130 +107,44 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// Open namespace.
GenerateNamespaceOpeners(printer);
- // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
- // functions, so that we can declare them to be friends of each class.
- printer->Print(
- "\n"
- "// Internal implementation detail -- do not call these.\n"
- "void $dllexport_decl$$adddescriptorsname$();\n",
- "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
- "dllexport_decl",
- options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
-
- printer->Print(
- // Note that we don't put dllexport_decl on these because they are only
- // called by the .pb.cc file in which they are defined.
- "void $assigndescriptorsname$();\n"
- "void $shutdownfilename$();\n"
- "\n",
- "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
- "shutdownfilename", GlobalShutdownFileName(file_->name()));
-
- // Generate forward declarations of classes.
- for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateForwardDeclaration(printer);
- }
+ GenerateGlobalStateFunctionDeclarations(printer);
+ GenerateMessageForwardDeclarations(printer);
printer->Print("\n");
- // Generate enum definitions.
- for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateEnumDefinitions(printer);
- }
- for (int i = 0; i < file_->enum_type_count(); i++) {
- enum_generators_[i]->GenerateDefinition(printer);
- }
+ GenerateEnumDefinitions(printer);
printer->Print(kThickSeparator);
printer->Print("\n");
- // Generate class definitions.
- for (int i = 0; i < file_->message_type_count(); i++) {
- if (i > 0) {
- printer->Print("\n");
- printer->Print(kThinSeparator);
- printer->Print("\n");
- }
- message_generators_[i]->GenerateClassDefinition(printer);
- }
+ GenerateMessageDefinitions(printer);
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
- if (HasGenericServices(file_)) {
- // Generate service definitions.
- for (int i = 0; i < file_->service_count(); i++) {
- if (i > 0) {
- printer->Print("\n");
- printer->Print(kThinSeparator);
- printer->Print("\n");
- }
- service_generators_[i]->GenerateDeclarations(printer);
- }
+ GenerateServiceDefinitions(printer);
- printer->Print("\n");
- printer->Print(kThickSeparator);
- printer->Print("\n");
- }
-
- // Declare extension identifiers.
- for (int i = 0; i < file_->extension_count(); i++) {
- extension_generators_[i]->GenerateDeclaration(printer);
- }
+ GenerateExtensionIdentifiers(printer);
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
-
- // Generate class inline methods.
- for (int i = 0; i < file_->message_type_count(); i++) {
- if (i > 0) {
- printer->Print(kThinSeparator);
- printer->Print("\n");
- }
- message_generators_[i]->GenerateInlineMethods(printer);
- }
-
- printer->Print(
- "\n"
- "// @@protoc_insertion_point(namespace_scope)\n");
+ GenerateInlineFunctionDefinitions(printer);
// Close up namespace.
GenerateNamespaceClosers(printer);
- // Emit GetEnumDescriptor specializations into google::protobuf namespace:
- if (HasDescriptorMethods(file_)) {
- // The SWIG conditional is to avoid a null-pointer dereference
- // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
- // namespace X { void Y<Z::W>(); }
- // which appears in GetEnumDescriptor() specializations.
- printer->Print(
- "\n"
- "#ifndef SWIG\n"
- "namespace google {\nnamespace protobuf {\n"
- "\n");
- for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
- }
- for (int i = 0; i < file_->enum_type_count(); i++) {
- enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
- }
- printer->Print(
- "\n"
- "} // namespace protobuf\n} // namespace google\n"
- "#endif // SWIG\n");
- }
+ // We need to specialize some templates in the ::google::protobuf namespace:
+ GenerateProto2NamespaceEnumSpecializations(printer);
printer->Print(
"\n"
"// @@protoc_insertion_point(global_scope)\n"
"\n");
- printer->Print(
- "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
- "filename_identifier", filename_identifier);
+ GenerateBottomHeaderGuard(printer);
}
void FileGenerator::GenerateSource(io::Printer* printer) {
@@ -417,6 +242,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
printer->Print(kThickSeparator);
printer->Print("\n");
message_generators_[i]->GenerateClassMethods(printer);
+
+ printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+ // Generate class inline methods.
+ message_generators_[i]->GenerateInlineMethods(printer,
+ /* is_inline = */ false);
+ printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n");
}
if (HasGenericServices(file_)) {
@@ -603,20 +434,52 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
string file_data;
file_proto.SerializeToString(&file_data);
- printer->Print(
- "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
-
- // Only write 40 bytes per line.
- 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))));
+ // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535
+ // bytes in length". Declare a static array of characters rather than use a
+ // string literal.
+ if (file_data.size() > 65535) {
+ printer->Print(
+ "static const char descriptor[] = {\n");
+ printer->Indent();
+
+ // Only write 25 bytes per line.
+ static const int kBytesPerLine = 25;
+ for (int i = 0; i < file_data.size();) {
+ for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
+ printer->Print(
+ "$char$, ",
+ "char", SimpleItoa(file_data[i]));
+ }
+ printer->Print(
+ "\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "};\n");
+
+ printer->Print(
+ "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n",
+ "size", SimpleItoa(file_data.size()));
+
+ } else {
+
+ printer->Print(
+ "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
+
+ // Only write 40 bytes per line.
+ 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))));
+ }
+ printer->Print(
+ ", $size$);\n",
+ "size", SimpleItoa(file_data.size()));
+
}
- printer->Print(
- ", $size$);\n",
- "size", SimpleItoa(file_data.size()));
// Call MessageFactory::InternalRegisterGeneratedFile().
printer->Print(
@@ -685,6 +548,294 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
}
}
+void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) {
+ string filename_identifier = FilenameIdentifier(file_->name());
+ // Generate top of header.
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n"
+ "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
+ "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
+ "\n"
+ "#include <string>\n"
+ "\n",
+ "filename", file_->name(),
+ "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) {
+ string filename_identifier = FilenameIdentifier(file_->name());
+ printer->Print(
+ "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
+ "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
+
+ printer->Print(
+ "#include <google/protobuf/stubs/common.h>\n"
+ "\n");
+
+ // Verify the protobuf library header version is compatible with the protoc
+ // version before going any further.
+ printer->Print(
+ "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
+ "#error This file was generated by a newer version of protoc which is\n"
+ "#error incompatible with your Protocol Buffer headers. Please update\n"
+ "#error your headers.\n"
+ "#endif\n"
+ "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
+ "#error This file was generated by an older version of protoc which is\n"
+ "#error incompatible with your Protocol Buffer headers. Please\n"
+ "#error regenerate this file with a newer version of protoc.\n"
+ "#endif\n"
+ "\n",
+ "min_header_version",
+ SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
+ "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
+
+ // OK, it's now safe to #include other files.
+ printer->Print(
+ "#include <google/protobuf/arena.h>\n"
+ "#include <google/protobuf/arenastring.h>\n"
+ "#include <google/protobuf/generated_message_util.h>\n");
+ if (UseUnknownFieldSet(file_)) {
+ printer->Print(
+ "#include <google/protobuf/metadata.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 (HasMapFields(file_)) {
+ printer->Print(
+ "#include <google/protobuf/map.h>\n");
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/map_field_inl.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/map_field_lite.h>\n");
+ }
+ }
+
+ if (HasEnumDefinitions(file_)) {
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/generated_enum_reflection.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/generated_enum_util.h>\n");
+ }
+ }
+
+ if (HasGenericServices(file_)) {
+ printer->Print(
+ "#include <google/protobuf/service.h>\n");
+ }
+
+ if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+ printer->Print(
+ "#include <google/protobuf/unknown_field_set.h>\n");
+ }
+
+
+ if (IsAnyMessage(file_)) {
+ printer->Print(
+ "#include \"google/protobuf/any.h\"\n");
+ }
+}
+
+void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
+ set<string> public_import_names;
+ for (int i = 0; i < file_->public_dependency_count(); i++) {
+ public_import_names.insert(file_->public_dependency(i)->name());
+ }
+
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ const string& name = file_->dependency(i)->name();
+ bool public_import = (public_import_names.count(name) != 0);
+
+
+ printer->Print(
+ "#include \"$dependency$.pb.h\"$iwyu$\n",
+ "dependency", StripProto(name),
+ "iwyu", (public_import) ? " // IWYU pragma: export" : "");
+ }
+}
+
+void FileGenerator::GenerateGlobalStateFunctionDeclarations(
+ io::Printer* printer) {
+ // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
+ // functions, so that we can declare them to be friends of each class.
+ printer->Print(
+ "\n"
+ "// Internal implementation detail -- do not call these.\n"
+ "void $dllexport_decl$$adddescriptorsname$();\n",
+ "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
+ "dllexport_decl",
+ options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+
+ printer->Print(
+ // Note that we don't put dllexport_decl on these because they are only
+ // called by the .pb.cc file in which they are defined.
+ "void $assigndescriptorsname$();\n"
+ "void $shutdownfilename$();\n"
+ "\n",
+ "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
+ "shutdownfilename", GlobalShutdownFileName(file_->name()));
+}
+
+void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
+ // Generate forward declarations of classes.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateMessageForwardDeclaration(printer);
+ }
+}
+
+void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
+ // Generate class definitions.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ message_generators_[i]->GenerateClassDefinition(printer);
+ }
+}
+
+void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) {
+ // Generate enum definitions.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateEnumDefinitions(printer);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateDefinition(printer);
+ }
+}
+
+void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) {
+ if (HasGenericServices(file_)) {
+ // Generate service definitions.
+ for (int i = 0; i < file_->service_count(); i++) {
+ if (i > 0) {
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ service_generators_[i]->GenerateDeclarations(printer);
+ }
+
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+ }
+}
+
+void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
+ // Declare extension identifiers.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ extension_generators_[i]->GenerateDeclaration(printer);
+ }
+}
+
+void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
+ // An aside about inline functions in .proto.h mode:
+ //
+ // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally
+ // moving much of the inline functions to the .pb.cc file, which can be a
+ // significant performance benefit for compilation time, at the expense
+ // of non-inline function calls.
+ //
+ // However, in .proto.h mode, the definition of the internal dependent
+ // base class must remain in the header, and can never be out-lined. The
+ // dependent base class also needs access to has-bit manipuation
+ // functions, so the has-bit functions must be unconditionally inlined in
+ // proto_h mode.
+ //
+ // This gives us three flavors of functions:
+ //
+ // 1. Functions on the message not used by the internal dependent base
+ // class: in .proto.h mode, only some functions are defined on the
+ // message class; others are defined on the dependent base class.
+ // These are guarded and can be out-lined. These are generated by
+ // GenerateInlineMethods, and include has_* bit functions in
+ // non-proto_h mode.
+ //
+ // 2. Functions on the internal dependent base class: these functions
+ // are dependent on a template parameter, so they always need to
+ // remain in the header.
+ //
+ // 3. Functions on the message that are used by the dependent base: the
+ // dependent base class down casts itself to the message
+ // implementation class to access these functions (the has_* bit
+ // manipulation functions). Unlike #1, these functions must
+ // unconditionally remain in the header. These are emitted by
+ // GenerateDependentInlineMethods, even though they are not actually
+ // dependent.
+
+ printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+ // Generate class inline methods.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ message_generators_[i]->GenerateInlineMethods(printer,
+ /* is_inline = */ true);
+ }
+ printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ // Methods of the dependent base class must always be inline in the header.
+ message_generators_[i]->GenerateDependentInlineMethods(printer);
+ }
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(namespace_scope)\n");
+}
+
+void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
+ io::Printer* printer) {
+ // Emit GetEnumDescriptor specializations into google::protobuf namespace:
+ if (HasEnumDefinitions(file_)) {
+ // The SWIG conditional is to avoid a null-pointer dereference
+ // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
+ // namespace X { void Y<Z::W>(); }
+ // which appears in GetEnumDescriptor() specializations.
+ printer->Print(
+ "\n"
+ "#ifndef SWIG\n"
+ "namespace google {\nnamespace protobuf {\n"
+ "\n");
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+ }
+ printer->Print(
+ "\n"
+ "} // namespace protobuf\n} // namespace google\n"
+ "#endif // SWIG\n");
+ }
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 0e06547d..e68f67bb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -80,6 +80,35 @@ class FileGenerator {
void GenerateNamespaceOpeners(io::Printer* printer);
void GenerateNamespaceClosers(io::Printer* printer);
+ // Generates top or bottom of a header file.
+ void GenerateTopHeaderGuard(io::Printer* printer);
+ void GenerateBottomHeaderGuard(io::Printer* printer);
+
+ // Generates #include directives.
+ void GenerateLibraryIncludes(io::Printer* printer);
+ void GenerateDependencyIncludes(io::Printer* printer);
+
+ // Generates a couple of different pieces before definitions:
+ void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
+
+ // Generates types for classes.
+ void GenerateMessageForwardDeclarations(io::Printer* printer);
+ void GenerateMessageDefinitions(io::Printer* printer);
+
+ // Generates enum definitions.
+ void GenerateEnumDefinitions(io::Printer* printer);
+
+ // Generates generic service definitions.
+ void GenerateServiceDefinitions(io::Printer* printer);
+
+ // Generates extension identifiers.
+ void GenerateExtensionIdentifiers(io::Printer* printer);
+
+ // Generates inline function defintions.
+ void GenerateInlineFunctionDefinitions(io::Printer* printer);
+
+ void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer);
+
const FileDescriptor* file_;
google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index c999b93f..99416372 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -82,6 +82,7 @@ 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.
+ //
Options file_options;
for (int i = 0; i < options.size(); i++) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 28c4dd54..0f3688d0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -51,6 +51,9 @@ namespace cpp {
namespace {
+static const char kAnyMessageName[] = "Any";
+static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+
string DotsToUnderscores(const string& name) {
return StringReplace(name, ".", "_", true);
}
@@ -162,6 +165,10 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
}
+string DependentBaseClassTemplateName(const Descriptor* descriptor) {
+ return ClassName(descriptor, false) + "_InternalBase";
+}
+
string SuperClassName(const Descriptor* descriptor) {
return HasDescriptorMethods(descriptor->file()) ?
"::google::protobuf::Message" : "::google::protobuf::MessageLite";
@@ -176,6 +183,14 @@ string FieldName(const FieldDescriptor* field) {
return result;
}
+string EnumValueName(const EnumValueDescriptor* enum_value) {
+ string result = enum_value->name();
+ if (kKeywords.count(result) > 0) {
+ result.append("_");
+ }
+ return result;
+}
+
string FieldConstantName(const FieldDescriptor *field) {
string field_name = UnderscoresToCamelCase(field->name(), true);
string result = "k" + field_name + "FieldNumber";
@@ -192,6 +207,47 @@ string FieldConstantName(const FieldDescriptor *field) {
return result;
}
+bool IsFieldDependent(const FieldDescriptor* field) {
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ return false;
+ }
+ if (field->containing_oneof() != NULL) {
+ // Oneof fields will always be dependent.
+ //
+ // This is a unique case for field codegen. Field generators are
+ // responsible for generating all the field-specific accessor
+ // functions, except for the clear_*() function; instead, field
+ // generators produce inline clearing code.
+ //
+ // For non-oneof fields, the Message class uses the inline clearing
+ // code to define the field's clear_*() function, as well as in the
+ // destructor. For oneof fields, the Message class generates a much
+ // more complicated clear_*() function, which clears only the oneof
+ // member that is set, in addition to clearing methods for each of the
+ // oneof members individually.
+ //
+ // Since oneofs do not have their own generator class, the Message code
+ // generation logic would be significantly complicated in order to
+ // split dependent and non-dependent manipulation logic based on
+ // whether the oneof truly needs to be dependent; so, for oneof fields,
+ // we just assume it (and its constituents) should be manipulated by a
+ // dependent base class function.
+ //
+ // This is less precise than how dependent message-typed fields are
+ // handled, but the cost is limited to only the generated code for the
+ // oneof field, which seems like an acceptable tradeoff.
+ return true;
+ }
+ if (field->file() == field->message_type()->file()) {
+ return false;
+ }
+ return true;
+}
+
+string DependentTypeName(const FieldDescriptor* field) {
+ return "InternalBase_" + field->name() + "_T";
+}
+
string FieldMessageTypeName(const FieldDescriptor* field) {
// Note: The Google-internal version of Protocol Buffers uses this function
// as a hook point for hacks to support legacy code.
@@ -352,9 +408,7 @@ string FilenameIdentifier(const string& filename) {
} else {
// Not alphanumeric. To avoid any possibility of name conflicts we
// use the hex code for the character.
- result.push_back('_');
- char buffer[kFastToBufferSize];
- result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
+ StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
}
}
return result;
@@ -508,6 +562,22 @@ bool IsStringOrMessage(const FieldDescriptor* field) {
return false;
}
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
+ GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
+ // Open-source protobuf release only supports STRING ctype.
+ return FieldOptions::STRING;
+
+}
+
+bool IsAnyMessage(const FileDescriptor* descriptor) {
+ return descriptor->name() == kAnyProtoFile;
+}
+
+bool IsAnyMessage(const Descriptor* descriptor) {
+ return descriptor->name() == kAnyMessageName &&
+ descriptor->file()->name() == kAnyProtoFile;
+}
+
} // 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 e60fa7c2..4bbf8303 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -66,6 +66,10 @@ extern const char kThinSeparator[];
string ClassName(const Descriptor* descriptor, bool qualified);
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
+// Name of the CRTP class template (for use with proto_h).
+// This is a class name, like "ProtoName_InternalBase".
+string DependentBaseClassTemplateName(const Descriptor* descriptor);
+
string SuperClassName(const Descriptor* descriptor);
// Get the (unqualified) name that should be used for this field in C++ code.
@@ -74,6 +78,9 @@ string SuperClassName(const Descriptor* descriptor);
// anyway, so normally this just returns field->name().
string FieldName(const FieldDescriptor* field);
+// Get the sanitized name that should be used for the given enum in C++ code.
+string EnumValueName(const EnumValueDescriptor* enum_value);
+
// Get the unqualified name that should be used for a field's field
// number constant.
string FieldConstantName(const FieldDescriptor *field);
@@ -85,6 +92,20 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) {
field->extension_scope() : field->containing_type();
}
+// Returns true if the given 'field_descriptor' has a message type that is
+// a dependency of the file where the field is defined (i.e., the field
+// type is defined in a different file than the message holding the field).
+//
+// This only applies to Message-typed fields. Enum-typed fields may refer
+// to an enum in a dependency; however, enums are specified and
+// forward-declared with an enum-base, so the definition is not required to
+// manipulate the field value.
+bool IsFieldDependent(const FieldDescriptor* field_descriptor);
+
+// Returns the name that should be used for forcing dependent lookup from a
+// dependent base class.
+string DependentTypeName(const FieldDescriptor* field);
+
// Returns the fully-qualified type name field->message_type(). Usually this
// is just ClassName(field->message_type(), true);
string FieldMessageTypeName(const FieldDescriptor* field);
@@ -211,6 +232,10 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) {
// Returns true if the field's CPPTYPE is string or message.
bool IsStringOrMessage(const FieldDescriptor* field);
+// For a string field, returns the effective ctype. If the actual ctype is
+// not supported, returns the default of STRING.
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field);
+
string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
inline bool HasFieldPresence(const FileDescriptor* file) {
@@ -235,6 +260,9 @@ inline bool SupportsArenas(const FieldDescriptor* field) {
return SupportsArenas(field->file());
}
+bool IsAnyMessage(const FileDescriptor* descriptor);
+bool IsAnyMessage(const Descriptor* descriptor);
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 0154eeb8..0ff0d27c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -31,6 +31,7 @@
#include <google/protobuf/compiler/cpp/cpp_map_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -72,14 +73,21 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
(*variables)["wrapper"] = "EntryWrapper";
}
- (*variables)["key_type"] =
- "::google::protobuf::FieldDescriptor::TYPE_" +
+ (*variables)["key_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
ToUpper(DeclaredTypeMethodName(key->type()));
- (*variables)["val_type"] =
- "::google::protobuf::FieldDescriptor::TYPE_" +
+ (*variables)["val_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
ToUpper(DeclaredTypeMethodName(val->type()));
(*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
- (*variables)["number"] = Int32ToString(descriptor->number());
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+
+ if (HasDescriptorMethods(descriptor->file())) {
+ (*variables)["lite"] = "";
+ } else {
+ (*variables)["lite"] = "Lite";
+ }
if (!IsProto3Field(descriptor) &&
val->type() == FieldDescriptor::TYPE_ENUM) {
@@ -102,33 +110,40 @@ MapFieldGenerator::~MapFieldGenerator() {}
void MapFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "typedef ::google::protobuf::internal::MapEntry<\n"
+ "typedef ::google::protobuf::internal::MapEntryLite<\n"
" $key_cpp$, $val_cpp$,\n"
- " $key_type$,\n"
- " $val_type$, $default_enum_value$>\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ >\n"
" $map_classname$;\n"
- "::google::protobuf::internal::MapField< $key_cpp$, $val_cpp$,"
- "$key_type$, $val_type$, $default_enum_value$ > $name$_;\n");
+ "::google::protobuf::internal::MapField$lite$<\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > $name$_;\n");
}
void MapFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+ "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
" $name$() const$deprecation$;\n"
- "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
" mutable_$name$()$deprecation$;\n");
}
void MapFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_map:$full_name$)\n"
" return $name$_.GetMap();\n"
"}\n"
- "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
" return $name$_.MutableMap();\n"
@@ -198,11 +213,29 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
" if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
" (*mutable_$name$())[entry->key()] =\n"
" static_cast<$val_cpp$>(*entry->mutable_value());\n"
- " } else {\n"
- " mutable_unknown_fields()->AddLengthDelimited($number$, data);\n"
+ " } else {\n");
+ if (HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(variables_,
+ " mutable_unknown_fields()"
+ "->AddLengthDelimited($number$, data);\n");
+ } else {
+ printer->Print(variables_,
+ " unknown_fields_stream.WriteVarint32($tag$);\n"
+ " unknown_fields_stream.WriteVarint32(data.size());\n"
+ " unknown_fields_stream.WriteString(data);\n");
+ }
+
+
+ printer->Print(variables_,
" }\n"
"}\n");
}
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "if (entry->GetArena() != NULL) entry.release();\n");
+ }
}
void MapFieldGenerator::
@@ -211,12 +244,32 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
"{\n"
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
- " it = $name$().begin(); it != $name$().end(); ++it) {\n"
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it) {\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
" $number$, *entry, output);\n"
- " }\n"
- "}\n");
+ " }\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print("}\n");
}
void MapFieldGenerator::
@@ -225,13 +278,33 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
"{\n"
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
- " it = $name$().begin(); it != $name$().end(); ++it) {\n"
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it) {\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
" $number$, *entry, target);\n"
- " }\n"
- "}\n");
+ " }\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print("}\n");
}
void MapFieldGenerator::
@@ -241,12 +314,32 @@ GenerateByteSize(io::Printer* printer) const {
"{\n"
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
- " it = $name$().begin(); it != $name$().end(); ++it) {\n"
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it) {\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
" total_size += ::google::protobuf::internal::WireFormatLite::\n"
" $declared_type$SizeNoVirtual(*entry);\n"
- " }\n"
- "}\n");
+ " }\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print("}\n");
}
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
index 0ff032fd..d27d4851 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -50,7 +50,8 @@ class MapFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index e71d35fa..b0e38755 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -64,10 +64,15 @@ using internal::WireFormatLite;
namespace {
-void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
- // Print the field's proto-syntax definition as a comment. We don't want to
- // print group bodies so we cut off after the first line.
- string def = field->DebugString();
+template <class T>
+void PrintFieldComment(io::Printer* printer, const T* field) {
+ // Print the field's (or oneof's) proto-syntax definition as a comment.
+ // We don't want to print group bodies so we cut off after the first
+ // line.
+ DebugStringOptions options;
+ options.elide_group_body = true;
+ options.elide_oneof_body = true;
+ string def = field->DebugStringWithOptions(options);
printer->Print("// $def$\n",
"def", def.substr(0, def.find_first_of('\n')));
}
@@ -87,8 +92,8 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); i++) {
fields[i] = descriptor->field(i);
}
- sort(fields, fields + descriptor->field_count(),
- FieldOrderingByNumber());
+ std::sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
return fields;
}
@@ -253,7 +258,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
// Sort by preferred location to keep fields as close to their original
// location as possible. Using stable_sort ensures that the output is
// consistent across runs.
- stable_sort(aligned_to_4.begin(), aligned_to_4.end());
+ std::stable_sort(aligned_to_4.begin(), aligned_to_4.end());
// Now group fields aligned to 4 bytes (or the 4-field groups created above)
// into pairs, and treat those like a single field aligned to 8 bytes.
@@ -269,7 +274,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
aligned_to_8.push_back(field_group);
}
// Sort by preferred location.
- stable_sort(aligned_to_8.begin(), aligned_to_8.end());
+ std::stable_sort(aligned_to_8.begin(), aligned_to_8.end());
// Now pull out all the FieldDescriptors in order.
fields->clear();
@@ -351,11 +356,11 @@ void CollectMapInfo(const Descriptor* descriptor,
default:
(*variables)["val"] = PrimitiveTypeName(val->cpp_type());
}
- (*variables)["key_type"] =
- "::google::protobuf::FieldDescriptor::TYPE_" +
+ (*variables)["key_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
ToUpper(DeclaredTypeMethodName(key->type()));
- (*variables)["val_type"] =
- "::google::protobuf::FieldDescriptor::TYPE_" +
+ (*variables)["val_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
ToUpper(DeclaredTypeMethodName(val->type()));
}
@@ -383,7 +388,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
enum_generators_(
new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
extension_generators_(new google::protobuf::scoped_ptr<
- ExtensionGenerator>[descriptor->extension_count()]) {
+ ExtensionGenerator>[descriptor->extension_count()]),
+ use_dependent_base_(false) {
for (int i = 0; i < descriptor->nested_type_count(); i++) {
nested_generators_[i].reset(
@@ -405,13 +411,16 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
if (descriptor->field(i)->is_required()) {
++num_required_fields_;
}
+ if (options.proto_h && IsFieldDependent(descriptor->field(i))) {
+ use_dependent_base_ = true;
+ }
}
}
MessageGenerator::~MessageGenerator() {}
void MessageGenerator::
-GenerateForwardDeclaration(io::Printer* printer) {
+GenerateMessageForwardDeclaration(io::Printer* printer) {
printer->Print("class $classname$;\n",
"classname", classname_);
@@ -420,7 +429,17 @@ GenerateForwardDeclaration(io::Printer* printer) {
// message cannot be a top level class, we just need to avoid calling
// GenerateForwardDeclaration here.
if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
- nested_generators_[i]->GenerateForwardDeclaration(printer);
+ nested_generators_[i]->GenerateMessageForwardDeclaration(printer);
+ }
+}
+
+void MessageGenerator::
+GenerateEnumForwardDeclaration(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateEnumForwardDeclaration(printer);
+ }
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateForwardDeclaration(printer);
}
}
@@ -446,6 +465,35 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
}
void MessageGenerator::
+GenerateDependentFieldAccessorDeclarations(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ PrintFieldComment(printer, field);
+
+ map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ // If the message is dependent, the inline clear_*() method will need
+ // to delete the message type, so it must be in the dependent base
+ // class. (See also GenerateFieldAccessorDeclarations.)
+ printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+ }
+ // Generate type-specific accessor declarations.
+ field_generators_.get(field).GenerateDependentAccessorDeclarations(printer);
+ printer->Print("\n");
+ }
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+ PrintFieldComment(printer, oneof);
+ printer->Print(
+ "void clear_$oneof_name$();\n",
+ "oneof_name", oneof->name());
+ }
+}
+
+void MessageGenerator::
GenerateFieldAccessorDeclarations(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
@@ -456,18 +504,35 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
SetCommonFieldVariables(field, &vars, options_);
vars["constant_name"] = FieldConstantName(field);
+ bool dependent_field = use_dependent_base_ && IsFieldDependent(field);
+ if (dependent_field) {
+ // If this field is dependent, the dependent base class determines
+ // the message type from the derived class (which is a template
+ // parameter). This typedef is for that:
+ printer->Print(
+ "private:\n"
+ "typedef $field_type$ $dependent_type$;\n"
+ "public:\n",
+ "field_type", FieldMessageTypeName(field),
+ "dependent_type", DependentTypeName(field));
+ }
+
if (field->is_repeated()) {
- printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
+ printer->Print(vars, "int $name$_size() const$deprecation$;\n");
} else if (HasHasMethod(field)) {
- printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
+ printer->Print(vars, "bool has_$name$() const$deprecation$;\n");
} else if (HasPrivateHasMethod(field)) {
printer->Print(vars,
"private:\n"
- "inline bool has_$name$() const$deprecation$;\n"
+ "bool has_$name$() const$deprecation$;\n"
"public:\n");
}
- printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
+ if (!dependent_field) {
+ // If this field is dependent, then its clear_() method is in the
+ // depenent base class. (See also GenerateDependentAccessorDeclarations.)
+ printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+ }
printer->Print(vars, "static const int $constant_name$ = $number$;\n");
// Generate type-specific accessor declarations.
@@ -486,7 +551,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
- "inline $camel_oneof_name$Case $oneof_name$_case() const;\n",
+ "$camel_oneof_name$Case $oneof_name$_case() const;\n",
"camel_oneof_name",
UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true),
"oneof_name", descriptor_->oneof_decl(i)->name());
@@ -494,7 +559,189 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
}
void MessageGenerator::
-GenerateFieldAccessorDefinitions(io::Printer* printer) {
+GenerateDependentFieldAccessorDefinitions(io::Printer* printer) {
+ if (!use_dependent_base_) return;
+
+ printer->Print("// $classname$\n\n", "classname",
+ DependentBaseClassTemplateName(descriptor_));
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ PrintFieldComment(printer, field);
+
+ // These functions are not really dependent: they are part of the
+ // (non-dependent) derived class. However, they need to live outside
+ // any #ifdef guards, so we treat them as if they were dependent.
+ //
+ // See the comment in FileGenerator::GenerateInlineFunctionDefinitions
+ // for a more complete explanation.
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+ vars["inline"] = "inline ";
+ if (field->containing_oneof()) {
+ vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
+ vars["oneof_name"] = field->containing_oneof()->name();
+ vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
+ GenerateOneofMemberHasBits(field, vars, printer);
+ } else if (!field->is_repeated()) {
+ // There will be no header guard, so this always has to be inline.
+ GenerateSingularFieldHasBits(field, vars, printer);
+ }
+ // vars needed for clear_(), which is in the dependent base:
+ // (See also GenerateDependentFieldAccessorDeclarations.)
+ vars["tmpl"] = "template<class T>\n";
+ vars["dependent_classname"] =
+ DependentBaseClassTemplateName(descriptor_) + "<T>";
+ vars["this_message"] = "reinterpret_cast<T*>(this)->";
+ vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+ GenerateFieldClear(field, vars, printer);
+ }
+
+ // Generate type-specific accessors.
+ field_generators_.get(field)
+ .GenerateDependentInlineAccessorDefinitions(printer);
+
+ printer->Print("\n");
+ }
+
+ // Generate has_$name$() and clear_has_$name$() functions for oneofs
+ // Similar to other has-bits, these must always be in the header if we
+ // are using a dependent base class.
+ GenerateOneofHasBits(printer, true /* is_inline */);
+}
+
+void MessageGenerator::
+GenerateSingularFieldHasBits(const FieldDescriptor* field,
+ map<string, string> vars,
+ io::Printer* printer) {
+ if (HasFieldPresence(descriptor_->file())) {
+ // N.B.: without field presence, we do not use has-bits or generate
+ // has_$name$() methods.
+ vars["has_array_index"] = SimpleItoa(field->index() / 32);
+ vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32),
+ strings::ZERO_PAD_8));
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+ "}\n"
+ "$inline$"
+ "void $classname$::set_has_$name$() {\n"
+ " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
+ "}\n"
+ "$inline$"
+ "void $classname$::clear_has_$name$() {\n"
+ " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
+ "}\n");
+ } else {
+ // Message fields have a has_$name$() method.
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ bool is_lazy = false;
+ if (is_lazy) {
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return !$name$_.IsCleared();\n"
+ "}\n");
+ } else {
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return !_is_default_instance_ && $name$_ != NULL;\n"
+ "}\n");
+ }
+ }
+ }
+}
+
+void MessageGenerator::
+GenerateOneofHasBits(io::Printer* printer, bool is_inline) {
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ map<string, string> vars;
+ vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ vars["cap_oneof_name"] =
+ ToUpper(descriptor_->oneof_decl(i)->name());
+ vars["classname"] = classname_;
+ vars["inline"] = (is_inline ? "inline " : "");
+ printer->Print(
+ vars,
+ "$inline$"
+ "bool $classname$::has_$oneof_name$() const {\n"
+ " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
+ "}\n"
+ "$inline$"
+ "void $classname$::clear_has_$oneof_name$() {\n"
+ " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
+ "}\n");
+ }
+}
+
+void MessageGenerator::
+GenerateOneofMemberHasBits(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer) {
+ // Singular field in a oneof
+ // N.B.: Without field presence, we do not use has-bits or generate
+ // has_$name$() methods, but oneofs still have set_has_$name$().
+ // Oneofs also have has_$name$() but only as a private helper
+ // method, so that generated code is slightly cleaner (vs. comparing
+ // _oneof_case_[index] against a constant everywhere).
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return $oneof_name$_case() == k$field_name$;\n"
+ "}\n");
+ printer->Print(vars,
+ "$inline$"
+ "void $classname$::set_has_$name$() {\n"
+ " _oneof_case_[$oneof_index$] = k$field_name$;\n"
+ "}\n");
+}
+
+void MessageGenerator::
+GenerateFieldClear(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer) {
+ // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and
+ // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is
+ // set by the Generate*Definitions functions.)
+ printer->Print(vars,
+ "$tmpl$"
+ "$inline$"
+ "void $dependent_classname$::clear_$name$() {\n");
+
+ printer->Indent();
+
+ if (field->containing_oneof()) {
+ // Clear this field only if it is the active field in this oneof,
+ // otherwise ignore
+ printer->Print(vars,
+ "if ($this_message$has_$name$()) {\n");
+ printer->Indent();
+ field_generators_.get(field).GenerateClearingCode(printer);
+ printer->Print(vars,
+ "$this_message$clear_has_$oneof_name$();\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ if (HasFieldPresence(descriptor_->file())) {
+ if (!field->is_repeated()) {
+ printer->Print(vars,
+ "$this_message$clear_has_$name$();\n");
+ }
+ }
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
+GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
printer->Print("// $classname$\n\n", "classname", classname_);
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -504,122 +751,49 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
map<string, string> vars;
SetCommonFieldVariables(field, &vars, options_);
+ vars["inline"] = is_inline ? "inline " : "";
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
printer->Print(vars,
- "inline int $classname$::$name$_size() const {\n"
+ "$inline$"
+ "int $classname$::$name$_size() const {\n"
" return $name$_.size();\n"
"}\n");
} else if (field->containing_oneof()) {
- // Singular field in a oneof
- // N.B.: Without field presence, we do not use has-bits or generate
- // has_$name$() methods, but oneofs still have set_has_$name$().
- // Oneofs also have has_$name$() but only as a private helper
- // method, so that generated code is slightly cleaner (vs. comparing
- // _oneof_case_[index] against a constant everywhere).
vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
vars["oneof_name"] = field->containing_oneof()->name();
vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
- printer->Print(vars,
- "inline bool $classname$::has_$name$() const {\n"
- " return $oneof_name$_case() == k$field_name$;\n"
- "}\n");
- printer->Print(vars,
- "inline void $classname$::set_has_$name$() {\n"
- " _oneof_case_[$oneof_index$] = k$field_name$;\n"
- "}\n");
+ if (!use_dependent_base_ || !IsFieldDependent(field)) {
+ GenerateOneofMemberHasBits(field, vars, printer);
+ }
} else {
// Singular field.
- if (HasFieldPresence(descriptor_->file())) {
- // N.B.: without field presence, we do not use has-bits or generate
- // has_$name$() methods.
- char buffer[kFastToBufferSize];
- vars["has_array_index"] = SimpleItoa(field->index() / 32);
- vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32),
- buffer);
- printer->Print(vars,
- "inline bool $classname$::has_$name$() const {\n"
- " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
- "}\n"
- "inline void $classname$::set_has_$name$() {\n"
- " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
- "}\n"
- "inline void $classname$::clear_has_$name$() {\n"
- " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
- "}\n"
- );
- } else {
- // Message fields have a has_$name$() method.
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- bool is_lazy = false;
- if (is_lazy) {
- printer->Print(vars,
- "inline bool $classname$::has_$name$() const {\n"
- " return !$name$_.IsCleared();\n"
- "}\n");
- } else {
- printer->Print(vars,
- "inline bool $classname$::has_$name$() const {\n"
- " return !_is_default_instance_ && $name$_ != NULL;\n"
- "}\n");
- }
- }
+ if (!use_dependent_base_ || !IsFieldDependent(field)) {
+ GenerateSingularFieldHasBits(field, vars, printer);
}
}
- // Generate clear_$name$()
- printer->Print(vars,
- "inline void $classname$::clear_$name$() {\n");
-
- printer->Indent();
-
- if (field->containing_oneof()) {
- // Clear this field only if it is the active field in this oneof,
- // otherwise ignore
- printer->Print(vars,
- "if (has_$name$()) {\n");
- printer->Indent();
- field_generators_.get(field).GenerateClearingCode(printer);
- printer->Print(vars,
- "clear_has_$oneof_name$();\n");
- printer->Outdent();
- printer->Print("}\n");
- } else {
- field_generators_.get(field).GenerateClearingCode(printer);
- if (HasFieldPresence(descriptor_->file())) {
- if (!field->is_repeated()) {
- printer->Print(vars,
- "clear_has_$name$();\n");
- }
- }
+ if (!use_dependent_base_ || !IsFieldDependent(field)) {
+ vars["tmpl"] = "";
+ vars["dependent_classname"] = vars["classname"];
+ vars["this_message"] = "";
+ vars["this_const_message"] = "";
+ GenerateFieldClear(field, vars, printer);
}
- printer->Outdent();
- printer->Print("}\n");
-
// Generate type-specific accessors.
- field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
+ field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
+ is_inline);
printer->Print("\n");
}
- // Generate has_$name$() and clear_has_$name$() functions for oneofs
- for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- map<string, string> vars;
- vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
- vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
- vars["cap_oneof_name"] =
- ToUpper(descriptor_->oneof_decl(i)->name());
- vars["classname"] = classname_;
- printer->Print(
- vars,
- "inline bool $classname$::has_$oneof_name$() const {\n"
- " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
- "}\n"
- "inline void $classname$::clear_has_$oneof_name$() {\n"
- " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
- "}\n");
+ if (!use_dependent_base_) {
+ // Generate has_$name$() and clear_has_$name$() functions for oneofs
+ // If we aren't using a dependent base, they can be with the other functions
+ // that are #ifdef-guarded.
+ GenerateOneofHasBits(printer, is_inline);
}
}
@@ -649,6 +823,34 @@ static bool CanClearByZeroing(const FieldDescriptor* field) {
}
void MessageGenerator::
+GenerateDependentBaseClassDefinition(io::Printer* printer) {
+ if (!use_dependent_base_) {
+ return;
+ }
+
+ map<string, string> vars;
+ vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+ vars["superclass"] = SuperClassName(descriptor_);
+
+ printer->Print(vars,
+ "template <class T>\n"
+ "class $classname$ : public $superclass$ {\n"
+ " public:\n");
+ printer->Indent();
+
+ printer->Print(vars,
+ "$classname$() {}\n"
+ "virtual ~$classname$() {}\n"
+ "\n");
+
+ // Generate dependent accessor methods for all fields.
+ GenerateDependentFieldAccessorDeclarations(printer);
+
+ printer->Outdent();
+ printer->Print("};\n");
+}
+
+void MessageGenerator::
GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// map entry message doesn't need class definition. Since map entry message
@@ -661,6 +863,11 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print("\n");
}
+ if (use_dependent_base_) {
+ GenerateDependentBaseClassDefinition(printer);
+ printer->Print("\n");
+ }
+
map<string, string> vars;
vars["classname"] = classname_;
vars["field_count"] = SimpleItoa(descriptor_->field_count());
@@ -670,11 +877,18 @@ GenerateClassDefinition(io::Printer* printer) {
} else {
vars["dllexport"] = options_.dllexport_decl + " ";
}
- vars["superclass"] = SuperClassName(descriptor_);
-
+ if (use_dependent_base_) {
+ vars["superclass"] =
+ DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
+ } else {
+ vars["superclass"] = SuperClassName(descriptor_);
+ }
printer->Print(vars,
- "class $dllexport$$classname$ : public $superclass$ {\n"
- " public:\n");
+ "class $dllexport$$classname$ : public $superclass$ {\n");
+ if (use_dependent_base_) {
+ printer->Print(vars, " friend class $superclass$;\n");
+ }
+ printer->Print(" public:\n");
printer->Indent();
printer->Print(vars,
@@ -783,6 +997,19 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print(vars,
"void UnsafeArenaSwap($classname$* other);\n");
}
+
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(vars,
+ "// implements Any -----------------------------------------------\n"
+ "\n"
+ "void PackFrom(const ::google::protobuf::Message& message);\n"
+ "bool UnpackTo(::google::protobuf::Message* message) const;\n"
+ "template<typename T> bool Is() const {\n"
+ " return _any_metadata_.Is<T>();\n"
+ "}\n"
+ "\n");
+ }
+
printer->Print(vars,
"void Swap($classname$* other);\n"
"\n"
@@ -974,11 +1201,18 @@ GenerateClassDefinition(io::Printer* printer) {
// Generate oneof function declarations
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- printer->Print(
- "inline bool has_$oneof_name$() const;\n"
- "void clear_$oneof_name$();\n"
- "inline void clear_has_$oneof_name$();\n\n",
- "oneof_name", descriptor_->oneof_decl(i)->name());
+ if (use_dependent_base_) {
+ printer->Print(
+ "inline bool has_$oneof_name$() const;\n"
+ "inline void clear_has_$oneof_name$();\n\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ } else {
+ printer->Print(
+ "inline bool has_$oneof_name$() const;\n"
+ "void clear_$oneof_name$();\n"
+ "inline void clear_has_$oneof_name$();\n\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
}
if (HasGeneratedMethods(descriptor_->file()) &&
@@ -1140,6 +1374,12 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
+ // Generate _any_metadata_ for the Any type.
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(vars,
+ "::google::protobuf::internal::AnyMetadata _any_metadata_;\n");
+ }
+
// Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
// friends so that they can access private static variables like
// default_instance_ and reflection_.
@@ -1173,18 +1413,33 @@ GenerateClassDefinition(io::Printer* printer) {
}
void MessageGenerator::
-GenerateInlineMethods(io::Printer* printer) {
+GenerateDependentInlineMethods(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need inline methods. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateInlineMethods here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+ nested_generators_[i]->GenerateDependentInlineMethods(printer);
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+
+ GenerateDependentFieldAccessorDefinitions(printer);
+}
+
+void MessageGenerator::
+GenerateInlineMethods(io::Printer* printer, bool is_inline) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// map entry message doesn't need inline methods. Since map entry message
// cannot be a top level class, we just need to avoid calling
// GenerateInlineMethods here.
if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
- nested_generators_[i]->GenerateInlineMethods(printer);
+ nested_generators_[i]->GenerateInlineMethods(printer, is_inline);
printer->Print(kThinSeparator);
printer->Print("\n");
}
- GenerateFieldAccessorDefinitions(printer);
+ GenerateFieldAccessorDefinitions(printer, is_inline);
// Generate oneof_case() functions.
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -1194,9 +1449,11 @@ GenerateInlineMethods(io::Printer* printer) {
descriptor_->oneof_decl(i)->name(), true);
vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ vars["inline"] = is_inline ? "inline " : "";
printer->Print(
vars,
- "inline $class_name$::$camel_oneof_name$Case $class_name$::"
+ "$inline$"
+ "$class_name$::$camel_oneof_name$Case $class_name$::"
"$oneof_name$_case() const {\n"
" return $class_name$::$camel_oneof_name$Case("
"_oneof_case_[$oneof_index$]);\n"
@@ -1226,7 +1483,9 @@ GenerateDescriptorDeclarations(io::Printer* printer) {
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
printer->Print(" ");
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+ EffectiveStringCType(field) != FieldOptions::STRING)) {
printer->Print("const ");
}
field_generators_.get(field).GeneratePrivateMembers(printer);
@@ -1395,8 +1654,8 @@ GenerateTypeRegistrations(io::Printer* printer) {
" ::google::protobuf::internal::MapEntry<\n"
" $key$,\n"
" $val$,\n"
- " $key_type$,\n"
- " $val_type$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
" $default_enum_value$>::CreateDefaultInstance(\n"
" $classname$_descriptor_));\n");
}
@@ -1492,6 +1751,19 @@ GenerateShutdownCode(io::Printer* printer) {
void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(
+ "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
+ " _any_metadata_.PackFrom(message);\n"
+ "}\n"
+ "\n"
+ "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
+ " return _any_metadata_.UnpackTo(message);\n"
+ "}\n"
+ "\n",
+ "classname", classname_);
+ }
+
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
enum_generators_[i]->GenerateMethods(printer);
}
@@ -1765,7 +2037,7 @@ GenerateArenaDestructorCode(io::Printer* printer) {
if (need_registration) {
printer->Print(
"inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
- " if (arena != NULL) {"
+ " if (arena != NULL) {\n"
" arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
" }\n"
"}\n",
@@ -1780,18 +2052,23 @@ GenerateArenaDestructorCode(io::Printer* printer) {
void MessageGenerator::
GenerateStructors(io::Printer* printer) {
- string superclass = SuperClassName(descriptor_);
- string initializer_with_arena;
- if (UseUnknownFieldSet(descriptor_->file())) {
- initializer_with_arena = "_internal_metadata_(arena)";
+ string superclass;
+ if (use_dependent_base_) {
+ superclass =
+ DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
} else {
- initializer_with_arena = "_arena_ptr_(arena)";
+ superclass = SuperClassName(descriptor_);
}
+ string initializer_with_arena = superclass + "()";
+
if (descriptor_->extension_range_count() > 0) {
- initializer_with_arena = string("\n _extensions_(arena)") +
- (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena;
+ initializer_with_arena += ",\n _extensions_(arena)";
+ }
+
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ initializer_with_arena += ",\n _internal_metadata_(arena)";
} else {
- initializer_with_arena = "\n " + initializer_with_arena;
+ initializer_with_arena += ",\n _arena_ptr_(arena)";
}
// Initialize member variables with arena constructor.
@@ -1802,16 +2079,21 @@ GenerateStructors(io::Printer* printer) {
FieldName(descriptor_->field(i)) + string("_(arena)");
}
}
- initializer_with_arena = superclass + "()" +
- (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena;
+
+ if (IsAnyMessage(descriptor_)) {
+ initializer_with_arena += ",\n _any_metadata_(&type_url, &value_)";
+ }
string initializer_null;
initializer_null = (UseUnknownFieldSet(descriptor_->file()) ?
- ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)");
+ ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)");
+ if (IsAnyMessage(descriptor_)) {
+ initializer_null += ", _any_metadata_(&type_url_, &value_)";
+ }
printer->Print(
"$classname$::$classname$()\n"
- " : $superclass$() $initializer$ {\n"
+ " : $superclass$()$initializer$ {\n"
" SharedCtor();\n"
" // @@protoc_insertion_point(constructor:$full_name$)\n"
"}\n",
@@ -1892,10 +2174,14 @@ GenerateStructors(io::Printer* printer) {
"full_name", descriptor_->full_name());
if (UseUnknownFieldSet(descriptor_->file())) {
printer->Print(
- ",\n _internal_metadata_(NULL) {\n");
+ ",\n _internal_metadata_(NULL)");
} else if (!UseUnknownFieldSet(descriptor_->file())) {
- printer->Print(",\n _arena_ptr_(NULL) {\n");
+ printer->Print(",\n _arena_ptr_(NULL)");
+ }
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(",\n _any_metadata_(&type_url_, &value_)");
}
+ printer->Print(" {\n");
printer->Print(
" SharedCtor();\n"
" MergeFrom(from);\n"
@@ -2038,17 +2324,16 @@ GenerateClear(io::Printer* printer) {
// Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0.
// The generated code uses two macros to help it clear runs of fields:
- // OFFSET_OF_FIELD_ computes the offset (in bytes) of a field in the Message.
+ // ZR_HELPER_(f1) - ZR_HELPER_(f0) computes the difference, in bytes, of the
+ // positions of two fields in the Message.
// ZR_ zeroes a non-empty range of fields via memset.
const char* macros =
- "#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \\\n"
- " &reinterpret_cast<$classname$*>(16)->f) - \\\n"
- " reinterpret_cast<char*>(16))\n\n"
- "#define ZR_(first, last) do { \\\n"
- " size_t f = OFFSET_OF_FIELD_(first); \\\n"
- " size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \\\n"
- " ::memset(&first, 0, n); \\\n"
- " } while (0)\n\n";
+ "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n"
+ " &reinterpret_cast<$classname$*>(16)->f)\n\n"
+ "#define ZR_(first, last) do {\\\n"
+ " ::memset(&first, 0,\\\n"
+ " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n"
+ "} while (0)\n\n";
for (int i = 0; i < runs_of_fields_.size(); i++) {
const vector<string>& run = runs_of_fields_[i];
if (run.size() < 2) continue;
@@ -2095,7 +2380,7 @@ GenerateClear(io::Printer* printer) {
} else {
if (HasFieldPresence(descriptor_->file())) {
printer->Print(
- "if (_has_bits_[$index$ / 32] & $mask$) {\n",
+ "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
"index", SimpleItoa(i / 8 * 8),
"mask", SimpleItoa(mask));
printer->Indent();
@@ -2123,7 +2408,11 @@ GenerateClear(io::Printer* printer) {
have_enclosing_if = true;
}
- field_generators_.get(field).GenerateClearingCode(printer);
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ printer->Print("clear_$name$();\n", "name", fieldname);
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ }
if (have_enclosing_if) {
printer->Outdent();
@@ -2137,7 +2426,7 @@ GenerateClear(io::Printer* printer) {
}
if (macros_are_needed) {
printer->Outdent();
- printer->Print("\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n");
+ printer->Print("\n#undef ZR_HELPER_\n#undef ZR_\n\n");
printer->Indent();
}
@@ -2146,7 +2435,11 @@ GenerateClear(io::Printer* printer) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->is_repeated()) {
- field_generators_.get(field).GenerateClearingCode(printer);
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ printer->Print("clear_$name$();\n", "name", FieldName(field));
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ }
}
}
@@ -2183,19 +2476,38 @@ void MessageGenerator::
GenerateOneofClear(io::Printer* printer) {
// Generated function clears the active field and union case (e.g. foo_case_).
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- printer->Print(
- "void $classname$::clear_$oneofname$() {\n",
- "classname", classname_,
- "oneofname", descriptor_->oneof_decl(i)->name());
+ map<string, string> oneof_vars;
+ oneof_vars["classname"] = classname_;
+ oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name();
+ string message_class;
+
+ if (use_dependent_base_) {
+ oneof_vars["tmpl"] = "template<class T>\n";
+ oneof_vars["inline"] = "inline ";
+ oneof_vars["dependent_classname"] =
+ DependentBaseClassTemplateName(descriptor_) + "<T>";
+ oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->";
+ message_class = "T::";
+ } else {
+ oneof_vars["tmpl"] = "";
+ oneof_vars["inline"] = "";
+ oneof_vars["dependent_classname"] = classname_;
+ oneof_vars["this_message"] = "";
+ }
+
+ printer->Print(oneof_vars,
+ "$tmpl$"
+ "$inline$"
+ "void $dependent_classname$::clear_$oneofname$() {\n");
printer->Indent();
- printer->Print(
- "switch($oneofname$_case()) {\n",
- "oneofname", descriptor_->oneof_decl(i)->name());
+ printer->Print(oneof_vars,
+ "switch($this_message$$oneofname$_case()) {\n");
printer->Indent();
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
printer->Print(
- "case k$field_name$: {\n",
+ "case $message_class$k$field_name$: {\n",
+ "message_class", message_class,
"field_name", UnderscoresToCamelCase(field->name(), true));
printer->Indent();
// We clear only allocated objects in oneofs
@@ -2212,16 +2524,20 @@ GenerateOneofClear(io::Printer* printer) {
"}\n");
}
printer->Print(
- "case $cap_oneof_name$_NOT_SET: {\n"
+ "case $message_class$$cap_oneof_name$_NOT_SET: {\n"
" break;\n"
"}\n",
+ "message_class", message_class,
"cap_oneof_name",
ToUpper(descriptor_->oneof_decl(i)->name()));
printer->Outdent();
printer->Print(
"}\n"
- "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n",
+ "$this_message$_oneof_case_[$oneof_index$] = "
+ "$message_class$$cap_oneof_name$_NOT_SET;\n",
+ "this_message", oneof_vars["this_message"],
"oneof_index", SimpleItoa(i),
+ "message_class", message_class,
"cap_oneof_name",
ToUpper(descriptor_->oneof_decl(i)->name()));
printer->Outdent();
@@ -2332,9 +2648,9 @@ GenerateMergeFrom(io::Printer* printer) {
// system, as the GOOGLE_CHECK above ensured that we have the same descriptor
// for each message.
printer->Print(
- "const $classname$* source =\n"
- " ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
- " &from);\n"
+ "const $classname$* source = \n"
+ " ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n"
+ " &from);\n"
"if (source == NULL) {\n"
" ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
"} else {\n"
@@ -2584,8 +2900,24 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Indent();
+ // Find repeated messages and groups now, to simplify what follows.
+ hash_set<int> fields_with_parse_loop;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+ if (field->is_repeated() &&
+ (field->type() == FieldDescriptor::TYPE_MESSAGE ||
+ field->type() == FieldDescriptor::TYPE_GROUP)) {
+ fields_with_parse_loop.insert(i);
+ }
+ }
+
+ // need_label is true if we generated "goto parse_$name$" while handling the
+ // previous field.
+ bool need_label = false;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = ordered_fields[i];
+ const bool loops = fields_with_parse_loop.count(i) > 0;
+ const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0;
PrintFieldComment(printer, field);
@@ -2599,14 +2931,21 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("if (tag == $commontag$) {\n",
"commontag", SimpleItoa(WireFormat::MakeTag(field)));
- if (i > 0 || (field->is_repeated() && !field->options().packed())) {
+ if (need_label ||
+ (field->is_repeated() && !field->is_packed() && !loops)) {
printer->Print(
- " parse_$name$:\n",
+ " parse_$name$:\n",
+ "name", field->name());
+ }
+ if (loops) {
+ printer->Print(
+ " DO_(input->IncrementRecursionDepth());\n"
+ " parse_loop_$name$:\n",
"name", field->name());
}
printer->Indent();
- if (field->options().packed()) {
+ if (field->is_packed()) {
field_generator.GenerateMergeFromCodedStreamWithPacking(printer);
} else {
field_generator.GenerateMergeFromCodedStream(printer);
@@ -2614,7 +2953,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Outdent();
// Emit code to parse unexpectedly packed or unpacked values.
- if (field->is_packable() && field->options().packed()) {
+ if (field->is_packed()) {
internal::WireFormatLite::WireType wiretype =
WireFormat::WireTypeForFieldType(field->type());
printer->Print("} else if (tag == $uncommontag$) {\n",
@@ -2624,7 +2963,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Indent();
field_generator.GenerateMergeFromCodedStream(printer);
printer->Outdent();
- } else if (field->is_packable() && !field->options().packed()) {
+ } else if (field->is_packable() && !field->is_packed()) {
internal::WireFormatLite::WireType wiretype =
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
printer->Print("} else if (tag == $uncommontag$) {\n",
@@ -2643,26 +2982,53 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// switch() is slow since it can't be predicted well. Insert some if()s
// here that attempt to predict the next tag.
- if (field->is_repeated() && !field->options().packed()) {
- // Expect repeats of this field.
+ // For non-packed repeated fields, expect the same tag again.
+ if (loops) {
+ printer->Print(
+ "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n",
+ "tag", SimpleItoa(WireFormat::MakeTag(field)),
+ "name", field->name());
+ } else if (field->is_repeated() && !field->is_packed()) {
printer->Print(
"if (input->ExpectTag($tag$)) goto parse_$name$;\n",
"tag", SimpleItoa(WireFormat::MakeTag(field)),
"name", field->name());
}
- if (i + 1 < descriptor_->field_count()) {
- // Expect the next field in order.
- const FieldDescriptor* next_field = ordered_fields[i + 1];
- printer->Print(
- "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
- "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
- "next_name", next_field->name());
- } else {
- // Expect EOF.
- // TODO(kenton): Expect group end-tag?
+ // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet?
+ bool emitted_goto_next_tag = false;
+
+ // For repeated messages/groups, we need to decrement recursion depth,
+ // unless the next tag is also for a repeated message/group.
+ if (loops) {
+ if (next_field_loops) {
+ const FieldDescriptor* next_field = ordered_fields[i + 1];
+ printer->Print(
+ "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n",
+ "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+ "next_name", next_field->name());
+ emitted_goto_next_tag = true;
+ }
printer->Print(
- "if (input->ExpectAtEnd()) goto success;\n");
+ "input->UnsafeDecrementRecursionDepth();\n");
+ }
+
+ // If there are more fields, expect the next one.
+ need_label = false;
+ if (!emitted_goto_next_tag) {
+ if (i + 1 == descriptor_->field_count()) {
+ // Expect EOF.
+ // TODO(kenton): Expect group end-tag?
+ printer->Print(
+ "if (input->ExpectAtEnd()) goto success;\n");
+ } else {
+ const FieldDescriptor* next_field = ordered_fields[i + 1];
+ printer->Print(
+ "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
+ "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+ "next_name", next_field->name());
+ need_label = true;
+ }
}
printer->Print(
@@ -2923,8 +3289,8 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
sorted_extensions.push_back(descriptor_->extension_range(i));
}
- sort(sorted_extensions.begin(), sorted_extensions.end(),
- ExtensionRangeSorter());
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeSorter());
// Merge the fields and the extension ranges, both sorted by field number.
int i, j;
@@ -2998,9 +3364,7 @@ static string ConditionalToCheckBitmasks(const vector<uint32>& masks) {
vector<string> parts;
for (int i = 0; i < masks.size(); i++) {
if (masks[i] == 0) continue;
- char buffer[kFastToBufferSize];
- FastHex32ToBuffer(masks[i], buffer);
- string m = StrCat("0x", buffer);
+ string m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8));
// Each xor evaluates to 0 if the expected bits are present.
parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")"));
}
@@ -3146,7 +3510,7 @@ GenerateByteSize(io::Printer* printer) {
} else {
if (HasFieldPresence(descriptor_->file())) {
printer->Print(
- "if (_has_bits_[$index$ / 32] & $mask$) {\n",
+ "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
"index", SimpleItoa(i),
"mask", SimpleItoa(mask));
printer->Indent();
@@ -3292,11 +3656,10 @@ GenerateIsInitialized(io::Printer* printer) {
}
if (mask != 0) {
- char buffer[kFastToBufferSize];
printer->Print(
"if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
"i", SimpleItoa(i),
- "mask", FastHex32ToBuffer(mask, buffer));
+ "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8)));
}
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index dfbc9af5..23dad10c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -67,7 +67,8 @@ class MessageGenerator {
// Header stuff.
// Generate foward declarations for this class and all its nested types.
- void GenerateForwardDeclaration(io::Printer* printer);
+ void GenerateMessageForwardDeclaration(io::Printer* printer);
+ void GenerateEnumForwardDeclaration(io::Printer* printer);
// Generate definitions of all nested enums (must come before class
// definitions because those classes use the enums definitions).
@@ -82,7 +83,10 @@ class MessageGenerator {
// Generate definitions of inline methods (placed at the end of the header
// file).
- void GenerateInlineMethods(io::Printer* printer);
+ void GenerateInlineMethods(io::Printer* printer, bool is_inline);
+
+ // Dependent methods are always inline.
+ void GenerateDependentInlineMethods(io::Printer* printer);
// Source file stuff.
@@ -115,8 +119,11 @@ class MessageGenerator {
private:
// Generate declarations and definitions of accessors for fields.
+ void GenerateDependentBaseClassDefinition(io::Printer* printer);
+ void GenerateDependentFieldAccessorDeclarations(io::Printer* printer);
void GenerateFieldAccessorDeclarations(io::Printer* printer);
- void GenerateFieldAccessorDefinitions(io::Printer* printer);
+ void GenerateDependentFieldAccessorDefinitions(io::Printer* printer);
+ void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
// Generate the field offsets array.
void GenerateOffsets(io::Printer* printer);
@@ -158,6 +165,21 @@ class MessageGenerator {
bool unbounded);
+ // Generates has_foo() functions and variables for singular field has-bits.
+ void GenerateSingularFieldHasBits(const FieldDescriptor* field,
+ map<string, string> vars,
+ io::Printer* printer);
+ // Generates has_foo() functions and variables for oneof field has-bits.
+ void GenerateOneofHasBits(io::Printer* printer, bool is_inline);
+ // Generates has_foo_bar() functions for oneof members.
+ void GenerateOneofMemberHasBits(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer);
+ // Generates the clear_foo() method for a field.
+ void GenerateFieldClear(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer);
+
const Descriptor* descriptor_;
string classname_;
Options options_;
@@ -168,6 +190,7 @@ class MessageGenerator {
google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
int num_required_fields_;
bool uses_string_;
+ bool use_dependent_base_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index b3cd0ba1..ba318d10 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -72,7 +72,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
MessageFieldGenerator::
MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
- : descriptor_(descriptor) {
+ : descriptor_(descriptor),
+ dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
SetMessageVariables(descriptor, &variables_, options);
}
@@ -84,77 +85,152 @@ GeneratePrivateMembers(io::Printer* printer) const {
}
void MessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+}
+
+void MessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "private:\n"
+ "void _slow_mutable_$name$()$deprecation$;\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ "void _slow_set_allocated_$name$(\n"
+ " ::google::protobuf::Arena* message_arena, $type$** $name$)$deprecation$;\n");
+ }
+ printer->Print(variables_,
+ "$type$* _slow_$release_name$()$deprecation$;\n"
+ "public:\n");
+ }
printer->Print(variables_,
- "inline const $type$& $name$() const$deprecation$;\n"
- "inline $type$* mutable_$name$()$deprecation$;\n"
- "inline $type$* $release_name$()$deprecation$;\n"
- "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+ "const $type$& $name$() const$deprecation$;\n"
+ "$type$* mutable_$name$()$deprecation$;\n"
+ "$type$* $release_name$()$deprecation$;\n"
+ "void set_allocated_$name$($type$* $name$)$deprecation$;\n");
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- "inline $type$* unsafe_arena_release_$name$()$deprecation$;\n"
- "inline void unsafe_arena_set_allocated_$name$(\n"
+ "$type$* unsafe_arena_release_$name$()$deprecation$;\n"
+ "void unsafe_arena_set_allocated_$name$(\n"
" $type$* $name$)$deprecation$;\n");
}
}
+void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
+ io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "void $classname$::_slow_mutable_$name$() {\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
+ " GetArenaNoVirtual());\n");
+ }
+ printer->Print(variables_,
+ "}\n"
+ "$type$* $classname$::_slow_$release_name$() {\n"
+ " if ($name$_ == NULL) {\n"
+ " return NULL;\n"
+ " } else {\n"
+ " $type$* temp = new $type$;\n"
+ " temp->MergeFrom(*$name$_);\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ " }\n"
+ "}\n"
+ "$type$* $classname$::unsafe_arena_release_$name$() {\n"
+ " $clear_hasbit$\n"
+ " $type$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ "}\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ // NOTE: the same logic is mirrored in weak_message_field.cc. Any
+ // arena-related semantics changes should be made in both places.
+ printer->Print(variables_,
+ "void $classname$::_slow_set_allocated_$name$(\n"
+ " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
+ " if (message_arena != NULL && \n"
+ " ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n"
+ " message_arena->Own(*$name$);\n"
+ " } else if (message_arena !=\n"
+ " ::google::protobuf::Arena::GetArena(*$name$)) {\n"
+ " $type$* new_$name$ = \n"
+ " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " message_arena);\n"
+ " new_$name$->CopyFrom(**$name$);\n"
+ " *$name$ = new_$name$;\n"
+ " }\n"
+ "}\n");
+ }
+ printer->Print(variables_,
+ "void $classname$::unsafe_arena_set_allocated_$name$(\n"
+ " $type$* $name$) {\n"
+ // If we're not on an arena, free whatever we were holding before.
+ // (If we are on arena, we can just forget the earlier pointer.)
+ " if (GetArenaNoVirtual() == NULL) {\n"
+ " delete $name$_;\n"
+ " }\n"
+ " $name$_ = $name$;\n"
+ " if ($name$) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
+ ":$full_name$)\n"
+ "}\n");
+ }
+}
+
void MessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$() const {\n"
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void MessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const $type$& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n");
PrintHandlingOptionalStaticInitializers(
- variables_, descriptor_->file(), printer,
+ variables, descriptor_->file(), printer,
// With static initializers.
" return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
// Without.
" return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
+ printer->Print(variables,
"}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
+ "$inline$ $type$* $classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
- " if ($name$_ == NULL) {\n");
- if (SupportsArenas(descriptor_->message_type())) {
- printer->Print(variables_,
- " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
- " GetArenaNoVirtual());\n");
- } else {
- printer->Print(variables_,
- " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
- " GetArenaNoVirtual());\n");
- }
- printer->Print(variables_, " }\n"
+ " if ($name$_ == NULL) {\n"
+ " _slow_mutable_$name$();"
+ " }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline $type$* $classname$::$release_name$() {\n"
+ "$inline$ $type$* $classname$::$release_name$() {\n"
" $clear_hasbit$\n"
" if (GetArenaNoVirtual() != NULL) {\n"
- " if ($name$_ == NULL) {\n"
- " return NULL;\n"
- " } else {\n"
- " $type$* temp = new $type$;\n"
- " temp->MergeFrom(*$name$_);\n"
- " $name$_ = NULL;\n"
- " return temp;\n"
- " }\n"
+ " return _slow_$release_name$();\n"
" } else {\n"
" $type$* temp = $name$_;\n"
" $name$_ = NULL;\n"
" return temp;\n"
" }\n"
"}\n"
- "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
- " $clear_hasbit$\n"
- " $type$* temp = $name$_;\n"
- " $name$_ = NULL;\n"
- " return temp;\n"
- "}\n"
- "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
- " if (GetArenaNoVirtual() == NULL) {\n"
+ "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"
+ " if (message_arena == NULL) {\n"
" delete $name$_;\n"
" }\n"
" if ($name$ != NULL) {\n");
@@ -164,26 +240,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
// so we might as well defer it. Otherwise, if incoming message is on a
// different ownership domain (specific arena, or the heap) than we are,
// copy to our arena (or heap, as the case may be).
- printer->Print(variables_,
- " if (GetArenaNoVirtual() != NULL && \n"
- " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n"
- " GetArenaNoVirtual()->Own($name$);\n"
- " } else if (GetArenaNoVirtual() !=\n"
- " ::google::protobuf::Arena::GetArena($name$)) {\n"
- " $type$* new_$name$ = \n"
- " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
- " GetArenaNoVirtual());\n"
- " new_$name$->CopyFrom(*$name$);\n"
- " $name$ = new_$name$;\n"
- " }\n");
+ printer->Print(variables,
+ " _slow_set_allocated_$name$(message_arena, &$name$);\n");
} else {
- printer->Print(variables_,
- " if (GetArenaNoVirtual() != NULL) {\n"
- " GetArenaNoVirtual()->Own($name$);\n"
+ printer->Print(variables,
+ " if (message_arena != NULL) {\n"
+ " message_arena->Own($name$);\n"
" }\n");
}
-
- printer->Print(variables_,
+ printer->Print(variables,
" }\n"
" $name$_ = $name$;\n"
" if ($name$) {\n"
@@ -192,27 +257,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $clear_hasbit$\n"
" }\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
- "}\n"
- "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
- " $type$* $name$) {\n"
- // If we're not on an arena, free whatever we were holding before.
- // (If we are on arena, we can just forget the earlier pointer.)
- " if (GetArenaNoVirtual() == NULL) {\n"
- " delete $name$_;\n"
- " }\n"
- " $name$_ = $name$;\n"
- " if ($name$) {\n"
- " $set_hasbit$\n"
- " } else {\n"
- " $clear_hasbit$\n"
- " }\n"
- " // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
- ":$full_name$)\n"
"}\n");
} else {
- printer->Print(variables_,
+ printer->Print(variables,
"}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
+ "$inline$ $type$* $classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
" if ($name$_ == NULL) {\n"
" $name$_ = new $type$;\n"
@@ -220,17 +269,17 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline $type$* $classname$::$release_name$() {\n"
+ "$inline$ $type$* $classname$::$release_name$() {\n"
" $clear_hasbit$\n"
" $type$* temp = $name$_;\n"
" $name$_ = NULL;\n"
" return temp;\n"
"}\n"
- "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
" delete $name$_;\n");
if (SupportsArenas(descriptor_->message_type())) {
- printer->Print(variables_,
+ printer->Print(variables,
" if ($name$ != NULL && $name$->GetArena() != NULL) {\n"
" $type$* new_$name$ = new $type$;\n"
" new_$name$->CopyFrom(*$name$);\n"
@@ -238,7 +287,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" }\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" $name$_ = $name$;\n"
" if ($name$) {\n"
" $set_hasbit$\n"
@@ -256,7 +305,7 @@ GenerateClearingCode(io::Printer* printer) const {
// If we don't have has-bits, message presence is indicated only by ptr !=
// NULL. Thus on clear, we need to delete the object.
printer->Print(variables_,
- "if ($name$_ != NULL) delete $name$_;\n"
+ "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n"
"$name$_ = NULL;\n");
} else {
printer->Print(variables_,
@@ -328,35 +377,42 @@ MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
void MessageOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void MessageOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$() const {\n"
+ printer->Print(variables,
+ "$inline$ const $type$& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return has_$name$() ? *$oneof_prefix$$name$_\n"
" : $type$::default_instance();\n"
"}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
+ "$inline$ $type$* $classname$::mutable_$name$() {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n");
if (SupportsArenas(descriptor_->message_type())) {
- printer->Print(variables_,
+ printer->Print(variables,
" $oneof_prefix$$name$_ = \n"
" ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
" GetArenaNoVirtual());\n");
} else {
- printer->Print(variables_,
+ printer->Print(variables,
" $oneof_prefix$$name$_ = \n"
" ::google::protobuf::Arena::Create< $type$ >(\n"
" GetArenaNoVirtual());\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $oneof_prefix$$name$_;\n"
"}\n"
- "inline $type$* $classname$::$release_name$() {\n"
+ "$inline$ $type$* $classname$::$release_name$() {\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" if (GetArenaNoVirtual() != NULL) {\n"
@@ -375,7 +431,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return NULL;\n"
" }\n"
"}\n"
- "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+ "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" $type$* temp = $oneof_prefix$$name$_;\n"
@@ -385,12 +441,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return NULL;\n"
" }\n"
"}\n"
- "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
" clear_$oneof_name$();\n"
" if ($name$) {\n");
if (SupportsArenas(descriptor_->message_type())) {
- printer->Print(variables_,
+ printer->Print(variables,
// If incoming message is on the heap and we are on an arena, just Own()
// it (see above). If it's on a different arena than we are or one of us
// is on the heap, we make a copy to our arena/heap.
@@ -406,19 +462,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $name$ = new_$name$;\n"
" }\n");
} else {
- printer->Print(variables_,
+ printer->Print(variables,
" if (GetArenaNoVirtual() != NULL) {\n"
" GetArenaNoVirtual()->Own($name$);\n"
" }\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" set_has_$name$();\n"
" $oneof_prefix$$name$_ = $name$;\n"
" }\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n"
- "inline void $classname$::unsafe_arena_set_allocated_$name$("
+ "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
"$type$* $name$) {\n"
// We rely on the oneof clear method to free the earlier contents of this
// oneof. We can directly use the pointer we're given to set the new
@@ -432,13 +488,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"$full_name$)\n"
"}\n");
} else {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$() const {\n"
+ printer->Print(variables,
+ "$inline$ const $type$& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return has_$name$() ? *$oneof_prefix$$name$_\n"
" : $type$::default_instance();\n"
"}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
+ "$inline$ $type$* $classname$::mutable_$name$() {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -447,7 +503,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $oneof_prefix$$name$_;\n"
"}\n"
- "inline $type$* $classname$::$release_name$() {\n"
+ "$inline$ $type$* $classname$::$release_name$() {\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" $type$* temp = $oneof_prefix$$name$_;\n"
@@ -457,18 +513,18 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return NULL;\n"
" }\n"
"}\n"
- "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
" clear_$oneof_name$();\n"
" if ($name$) {\n");
if (SupportsArenas(descriptor_->message_type())) {
- printer->Print(variables_,
+ printer->Print(variables,
" if ($name$->GetArena() != NULL) {\n"
" $type$* new_$name$ = new $type$;\n"
" new_$name$->CopyFrom(*$name$);\n"
" $name$ = new_$name$;\n"
" }\n");
}
- printer->Print(variables_,
+ printer->Print(variables,
" set_has_$name$();\n"
" $oneof_prefix$$name$_ = $name$;\n"
" }\n"
@@ -519,40 +575,51 @@ GeneratePrivateMembers(io::Printer* printer) const {
}
void RepeatedMessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+}
+
+void RepeatedMessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline const $type$& $name$(int index) const$deprecation$;\n"
- "inline $type$* mutable_$name$(int index)$deprecation$;\n"
- "inline $type$* add_$name$()$deprecation$;\n");
+ "const $type$& $name$(int index) const$deprecation$;\n"
+ "$type$* mutable_$name$(int index)$deprecation$;\n"
+ "$type$* add_$name$()$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+ "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
" $name$() const$deprecation$;\n"
- "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+ "::google::protobuf::RepeatedPtrField< $type$ >*\n"
" mutable_$name$()$deprecation$;\n");
}
void RepeatedMessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$(int index) const {\n"
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const $type$& $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.$cppget$(index);\n"
"}\n"
- "inline $type$* $classname$::mutable_$name$(int index) {\n"
+ "$inline$ $type$* $classname$::mutable_$name$(int index) {\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_.Mutable(index);\n"
"}\n"
- "inline $type$* $classname$::add_$name$() {\n"
+ "$inline$ $type$* $classname$::add_$name$() {\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
" return $name$_.Add();\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+ "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
@@ -583,11 +650,13 @@ void RepeatedMessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+ "DO_(::google::protobuf::internal::WireFormatLite::"
+ "ReadMessageNoVirtualNoRecursionDepth(\n"
" input, add_$name$()));\n");
} else {
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
+ "DO_(::google::protobuf::internal::WireFormatLite::"
+ "ReadGroupNoVirtualNoRecursionDepth(\n"
" $number$, input, add_$name$()));\n");
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index 2dff3144..9ddf9643 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -52,8 +52,12 @@ class MessageFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
@@ -65,6 +69,7 @@ class MessageFieldGenerator : public FieldGenerator {
protected:
const FieldDescriptor* descriptor_;
+ const bool dependent_field_;
map<string, string> variables_;
private:
@@ -78,7 +83,10 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
~MessageOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {}
void GenerateClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
@@ -95,8 +103,11 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 0c99cff1..4463f200 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -41,12 +41,13 @@ namespace protobuf {
namespace compiler {
namespace cpp {
-// Generator options:
+// Generator options (see generator.cc for a description of each):
struct Options {
- Options() : safe_boundary_check(false) {
+ Options() : safe_boundary_check(false), proto_h(false) {
}
string dllexport_decl;
bool safe_boundary_check;
+ bool proto_h;
};
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 9a2c930e..9f929d37 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -117,18 +117,20 @@ GeneratePrivateMembers(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$() const$deprecation$;\n"
- "inline void set_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$() const$deprecation$;\n"
+ "void set_$name$($type$ value)$deprecation$;\n");
}
void PrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n"
+ "$inline$ void $classname$::set_$name$($type$ value) {\n"
" $set_hasbit$\n"
" $name$_ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
@@ -204,16 +206,18 @@ PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
void PrimitiveOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return $oneof_prefix$$name$_;\n"
" }\n"
" return $default$;\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n"
+ "$inline$ void $classname$::set_$name$($type$ value) {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -258,7 +262,7 @@ RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
: descriptor_(descriptor) {
SetPrimitiveVariables(descriptor, &variables_, options);
- if (descriptor->options().packed()) {
+ if (descriptor->is_packed()) {
variables_["packed_reader"] = "ReadPackedPrimitive";
variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
} else {
@@ -273,7 +277,7 @@ void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField< $type$ > $name$_;\n");
- if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
+ if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
@@ -282,38 +286,40 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$(int index) const$deprecation$;\n"
- "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
- "inline void add_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$(int index) const$deprecation$;\n"
+ "void set_$name$(int index, $type$ value)$deprecation$;\n"
+ "void add_$name$($type$ value)$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+ "const ::google::protobuf::RepeatedField< $type$ >&\n"
" $name$() const$deprecation$;\n"
- "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+ "::google::protobuf::RepeatedField< $type$ >*\n"
" mutable_$name$()$deprecation$;\n");
}
void RepeatedPrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.Get(index);\n"
"}\n"
- "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+ "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"
" $name$_.Set(index, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::add_$name$($type$ value) {\n"
+ "$inline$ void $classname$::add_$name$($type$ value) {\n"
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+ "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
@@ -358,7 +364,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -371,7 +377,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
" this->$name$(i), output);\n");
@@ -385,7 +391,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -399,7 +405,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
@@ -429,7 +435,7 @@ GenerateByteSize(io::Printer* printer) const {
"data_size = $fixed_size$ * this->$name$_size();\n");
}
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 97b5e867..fcd7d684 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -53,7 +53,8 @@ class PrimitiveFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
@@ -78,7 +79,8 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
~PrimitiveOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
@@ -97,7 +99,8 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
index a8f303da..226c2aa0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -301,7 +301,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
printer->Print(vars_,
" default:\n"
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
- " return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
+ " return *static_cast< ::google::protobuf::Message*>(NULL);\n"
" }\n"
"}\n"
"\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 04ed08c9..1a3896a1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -127,7 +127,11 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
// files that applied the ctype. The field can still be accessed via the
// reflection interface since the reflection interface is independent of
// the string's underlying representation.
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+
+ bool unknown_ctype =
+ descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(
" private:\n"
@@ -136,23 +140,23 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
- "inline const ::std::string& $name$() const$deprecation$;\n"
- "inline void set_$name$(const ::std::string& value)$deprecation$;\n"
- "inline void set_$name$(const char* value)$deprecation$;\n"
- "inline void set_$name$(const $pointer_type$* value, size_t size)"
+ "const ::std::string& $name$() const$deprecation$;\n"
+ "void set_$name$(const ::std::string& value)$deprecation$;\n"
+ "void set_$name$(const char* value)$deprecation$;\n"
+ "void set_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
- "inline ::std::string* mutable_$name$()$deprecation$;\n"
- "inline ::std::string* $release_name$()$deprecation$;\n"
- "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
+ "::std::string* mutable_$name$()$deprecation$;\n"
+ "::std::string* $release_name$()$deprecation$;\n"
+ "void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- "inline ::std::string* unsafe_arena_release_$name$()$deprecation$;\n"
- "inline void unsafe_arena_set_allocated_$name$(\n"
+ "::std::string* unsafe_arena_release_$name$()$deprecation$;\n"
+ "void unsafe_arena_set_allocated_$name$(\n"
" ::std::string* $name$)$deprecation$;\n");
}
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(" public:\n");
printer->Indent();
@@ -160,25 +164,28 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
void StringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\n"
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.Get($default_variable$);\n"
"}\n"
- "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
" $set_hasbit$\n"
" $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::set_$name$(const char* value) {\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
" $set_hasbit$\n"
" $name$_.Set($default_variable$, $string_piece$(value),\n"
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
- "inline "
+ "$inline$ "
"void $classname$::set_$name$(const $pointer_type$* value,\n"
" size_t size) {\n"
" $set_hasbit$\n"
@@ -186,22 +193,22 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
"}\n"
- "inline ::std::string* $classname$::$release_name$() {\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
" $clear_hasbit$\n"
" return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"
"}\n"
- "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+ "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
" GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
" $clear_hasbit$\n"
" return $name$_.UnsafeArenaRelease($default_variable$,\n"
" GetArenaNoVirtual());\n"
"}\n"
- "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
" if ($name$ != NULL) {\n"
" $set_hasbit$\n"
" } else {\n"
@@ -211,7 +218,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n"
- "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
+ "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(\n"
" ::std::string* $name$) {\n"
" GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
" if ($name$ != NULL) {\n"
@@ -219,29 +226,28 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" } else {\n"
" $clear_hasbit$\n"
" }\n"
- " $set_hasbit$\n"
" $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
" $name$, GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n");
} else {
// No-arena case.
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\n"
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.GetNoArena($default_variable$);\n"
"}\n"
- "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
" $set_hasbit$\n"
" $name$_.SetNoArena($default_variable$, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::set_$name$(const char* value) {\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
" $set_hasbit$\n"
" $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
- "inline "
+ "$inline$ "
"void $classname$::set_$name$(const $pointer_type$* value, "
"size_t size) {\n"
" $set_hasbit$\n"
@@ -249,16 +255,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $string_piece$(reinterpret_cast<const char*>(value), size));\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_.MutableNoArena($default_variable$);\n"
"}\n"
- "inline ::std::string* $classname$::$release_name$() {\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
" $clear_hasbit$\n"
" return $name$_.ReleaseNoArena($default_variable$);\n"
"}\n"
- "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
" if ($name$ != NULL) {\n"
" $set_hasbit$\n"
" } else {\n"
@@ -422,17 +428,20 @@ StringOneofFieldGenerator(const FieldDescriptor* descriptor,
StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
void StringOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\n"
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return $oneof_prefix$$name$_.Get($default_variable$);\n"
" }\n"
" return *$default_variable$;\n"
"}\n"
- "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -442,7 +451,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::set_$name$(const char* value) {\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -452,7 +461,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $string_piece$(value), GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
- "inline "
+ "$inline$ "
"void $classname$::set_$name$(const $pointer_type$* value,\n"
" size_t size) {\n"
" if (!has_$name$()) {\n"
@@ -465,7 +474,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -475,7 +484,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::$release_name$() {\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" return $oneof_prefix$$name$_.Release($default_variable$,\n"
@@ -484,7 +493,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return NULL;\n"
" }\n"
"}\n"
- "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+ "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
" GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
@@ -494,7 +503,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return NULL;\n"
" }\n"
"}\n"
- "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
" if (!has_$name$()) {\n"
" $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
" }\n"
@@ -506,7 +515,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" }\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n"
- "inline void $classname$::unsafe_arena_set_allocated_$name$("
+ "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
"::std::string* $name$) {\n"
" GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
" if (!has_$name$()) {\n"
@@ -522,15 +531,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"}\n");
} else {
// No-arena case.
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\n"
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n"
" }\n"
" return *$default_variable$;\n"
"}\n"
- "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
@@ -540,7 +549,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::set_$name$(const char* value) {\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -550,7 +559,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $string_piece$(value));\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
- "inline "
+ "$inline$ "
"void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
@@ -561,7 +570,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" reinterpret_cast<const char*>(value), size));\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -570,7 +579,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
"}\n"
- "inline ::std::string* $classname$::$release_name$() {\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
@@ -578,7 +587,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return NULL;\n"
" }\n"
"}\n"
- "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
" if (!has_$name$()) {\n"
" $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
" }\n"
@@ -670,7 +679,10 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
// See comment above about unknown ctypes.
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+ bool unknown_ctype =
+ descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(
" private:\n"
@@ -679,26 +691,26 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
- "inline const ::std::string& $name$(int index) const$deprecation$;\n"
- "inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
- "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
- "inline void set_$name$(int index, const char* value)$deprecation$;\n"
- "inline "
+ "const ::std::string& $name$(int index) const$deprecation$;\n"
+ "::std::string* mutable_$name$(int index)$deprecation$;\n"
+ "void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
+ "void set_$name$(int index, const char* value)$deprecation$;\n"
+ ""
"void set_$name$(int index, const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
- "inline ::std::string* add_$name$()$deprecation$;\n"
- "inline void add_$name$(const ::std::string& value)$deprecation$;\n"
- "inline void add_$name$(const char* value)$deprecation$;\n"
- "inline void add_$name$(const $pointer_type$* value, size_t size)"
+ "::std::string* add_$name$()$deprecation$;\n"
+ "void add_$name$(const ::std::string& value)$deprecation$;\n"
+ "void add_$name$(const char* value)$deprecation$;\n"
+ "void add_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
+ "const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
"$deprecation$;\n"
- "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
+ "::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
"$deprecation$;\n");
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(" public:\n");
printer->Indent();
@@ -706,54 +718,57 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
void RepeatedStringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.$cppget$(index);\n"
"}\n"
- "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$(int index) {\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_.Mutable(index);\n"
"}\n"
- "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+ "$inline$ void $classname$::set_$name$(int index, const ::std::string& value) {\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
" $name$_.Mutable(index)->assign(value);\n"
"}\n"
- "inline void $classname$::set_$name$(int index, const char* value) {\n"
+ "$inline$ void $classname$::set_$name$(int index, const char* value) {\n"
" $name$_.Mutable(index)->assign(value);\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
- "inline void "
+ "$inline$ void "
"$classname$::set_$name$"
"(int index, const $pointer_type$* value, size_t size) {\n"
" $name$_.Mutable(index)->assign(\n"
" reinterpret_cast<const char*>(value), size);\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::add_$name$() {\n"
+ "$inline$ ::std::string* $classname$::add_$name$() {\n"
" return $name$_.Add();\n"
"}\n"
- "inline void $classname$::add_$name$(const ::std::string& value) {\n"
+ "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n"
" $name$_.Add()->assign(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n"
- "inline void $classname$::add_$name$(const char* value) {\n"
+ "$inline$ void $classname$::add_$name$(const char* value) {\n"
" $name$_.Add()->assign(value);\n"
" // @@protoc_insertion_point(field_add_char:$full_name$)\n"
"}\n"
- "inline void "
+ "$inline$ void "
"$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
" $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
" // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
+ "$inline$ ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 0a5ca440..d1f19cd9 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -54,7 +54,8 @@ class StringFieldGenerator : public FieldGenerator {
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateStaticMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
@@ -83,7 +84,8 @@ class StringOneofFieldGenerator : public StringFieldGenerator {
~StringOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
@@ -103,7 +105,8 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
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 4fa3c144..4e25b2ea 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -131,6 +131,24 @@ message TestConflictingSymbolNamesExtension { // NO_PROTO3
} // NO_PROTO3
} // NO_PROTO3
+message TestConflictingEnumNames { // NO_PROTO3
+ enum NestedConflictingEnum { // NO_PROTO3
+ and = 1; // NO_PROTO3
+ class = 2; // NO_PROTO3
+ int = 3; // NO_PROTO3
+ typedef = 4; // NO_PROTO3
+ XOR = 5; // NO_PROTO3
+ } // NO_PROTO3
+
+ optional NestedConflictingEnum conflicting_enum = 1; // NO_PROTO3
+} // NO_PROTO3
+
+enum ConflictingEnum { // NO_PROTO3
+ NOT_EQ = 1; // NO_PROTO3
+ volatile = 2; // NO_PROTO3
+ return = 3; // NO_PROTO3
+} // NO_PROTO3
+
message DummyMessage {}
service TestConflictingMethodNames {
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
new file mode 100644
index 00000000..cb6ca1b1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that proto2 compiler can generate valid code when the enum value
+// is INT_MAX. Note that this is a compile-only test and this proto is not
+// referenced in any C++ code.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message TestLargeEnumValue {
+ enum EnumWithLargeValue {
+ VALUE_1 = 1;
+ VALUE_MAX = 0x7fffffff;
+ }
+}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 2a04b293..bd1c0fde 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -55,6 +55,7 @@
#include <google/protobuf/unittest.pb.h>
#include <google/protobuf/unittest_optimize_for.pb.h>
#include <google/protobuf/unittest_embed_optimize_for.pb.h>
+#include <google/protobuf/unittest_enormous_descriptor.pb.h>
#include <google/protobuf/unittest_no_generic_services.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
@@ -130,6 +131,17 @@ TEST(GeneratedDescriptorTest, IdenticalDescriptors) {
generated_decsriptor_proto.DebugString());
}
+// Test that generated code has proper descriptors:
+// Touch a descriptor generated from an enormous message to validate special
+// handling for descriptors exceeding the C++ standard's recommended minimum
+// limit for string literal size
+TEST(GeneratedDescriptorTest, EnormousDescriptor) {
+ const Descriptor* generated_descriptor =
+ TestEnormousDescriptor::descriptor();
+
+ EXPECT_TRUE(generated_descriptor != NULL);
+}
+
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
// ===================================================================
@@ -794,6 +806,21 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) {
message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
}
+TEST(GeneratedMessageTest, TestConflictingEnumNames) {
+ protobuf_unittest::TestConflictingEnumNames message;
+ message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_);
+ EXPECT_EQ(1, message.conflicting_enum());
+ message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_XOR);
+ EXPECT_EQ(5, message.conflicting_enum());
+
+
+ protobuf_unittest::ConflictingEnum conflicting_enum;
+ conflicting_enum = protobuf_unittest::NOT_EQ;
+ EXPECT_EQ(1, conflicting_enum);
+ conflicting_enum = protobuf_unittest::return_;
+ EXPECT_EQ(3, conflicting_enum);
+}
+
#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
TEST(GeneratedMessageTest, TestOptimizedForSize) {
@@ -926,6 +953,22 @@ TEST(GeneratedMessageTest, ExtensionConstantValues) {
EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51);
}
+TEST(GeneratedMessageTest, ParseFromTruncated) {
+ const string long_string = string(128, 'q');
+ FileDescriptorProto p;
+ p.add_extension()->set_name(long_string);
+ const string msg = p.SerializeAsString();
+ int successful_count = 0;
+ for (int i = 0; i <= msg.size(); i++) {
+ if (p.ParseFromArray(msg.c_str(), i)) {
+ ++successful_count;
+ }
+ }
+ // We don't really care about how often we succeeded.
+ // As long as we didn't crash, we're happy.
+ EXPECT_GE(successful_count, 1);
+}
+
// ===================================================================
TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
@@ -1377,6 +1420,12 @@ class OneofTest : public testing::Test {
case unittest::TestOneof2::kFooString:
EXPECT_TRUE(message.has_foo_string());
break;
+ case unittest::TestOneof2::kFooCord:
+ EXPECT_TRUE(message.has_foo_cord());
+ break;
+ case unittest::TestOneof2::kFooStringPiece:
+ EXPECT_TRUE(message.has_foo_string_piece());
+ break;
case unittest::TestOneof2::kFooBytes:
EXPECT_TRUE(message.has_foo_bytes());
break;
@@ -1389,6 +1438,9 @@ class OneofTest : public testing::Test {
case unittest::TestOneof2::kFoogroup:
EXPECT_TRUE(message.has_foogroup());
break;
+ case unittest::TestOneof2::kFooLazyMessage:
+ EXPECT_TRUE(message.has_foo_lazy_message());
+ break;
case unittest::TestOneof2::FOO_NOT_SET:
break;
}
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
new file mode 100644
index 00000000..cb6ca1b1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that proto2 compiler can generate valid code when the enum value
+// is INT_MAX. Note that this is a compile-only test and this proto is not
+// referenced in any C++ code.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message TestLargeEnumValue {
+ enum EnumWithLargeValue {
+ VALUE_1 = 1;
+ VALUE_MAX = 0x7fffffff;
+ }
+}
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc
new file mode 100644
index 00000000..0e8f9836
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) :
+ SourceGeneratorBase(descriptor->file()),
+ descriptor_(descriptor) {
+}
+
+EnumGenerator::~EnumGenerator() {
+}
+
+void EnumGenerator::Generate(io::Printer* printer) {
+ WriteGeneratedCodeAttributes(printer);
+ printer->Print("$access_level$ enum $name$ {\n",
+ "access_level", class_access_level(),
+ "name", descriptor_->name());
+ printer->Indent();
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ printer->Print("$name$ = $number$,\n",
+ "name", descriptor_->value(i)->name(),
+ "number", SimpleItoa(descriptor_->value(i)->number()));
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print("\n");
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.h b/src/google/protobuf/compiler/csharp/csharp_enum.h
new file mode 100644
index 00000000..2cf2fad4
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.h
@@ -0,0 +1,63 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class EnumGenerator : public SourceGeneratorBase {
+ public:
+ EnumGenerator(const EnumDescriptor* descriptor);
+ ~EnumGenerator();
+
+ void Generate(io::Printer* printer);
+
+ private:
+ const EnumDescriptor* descriptor_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
new file mode 100644
index 00000000..d38fb1ed
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
@@ -0,0 +1,119 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : PrimitiveFieldGenerator(descriptor, fieldOrdinal) {
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {
+}
+
+void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$name$_ = ($type_name$) input.ReadEnum();\n");
+}
+
+void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "if ($has_property_check$) {\n"
+ " output.WriteRawTag($tag_bytes$);\n"
+ " output.WriteEnum((int) $property_name$);\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x)");
+}
+
+EnumOneofFieldGenerator::EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal) {
+}
+
+EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
+}
+
+void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ // TODO(jonskeet): What about if we read the default value?
+ printer->Print(
+ variables_,
+ "$oneof_name$_ = input.ReadEnum();\n"
+ "$oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n");
+}
+
+void EnumOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " output.WriteRawTag($tag_bytes$);\n"
+ " output.WriteEnum((int) $property_name$);\n"
+ "}\n");
+}
+
+void EnumOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
+ "}\n");
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h
new file mode 100644
index 00000000..08364157
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h
@@ -0,0 +1,77 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class EnumFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+ EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~EnumFieldGenerator();
+
+ virtual void GenerateCodecCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
+ public:
+ EnumOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~EnumOneofFieldGenerator();
+
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
new file mode 100644
index 00000000..cd29bcf9
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -0,0 +1,425 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <limits>
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/mathlimits.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+void FieldGeneratorBase::SetCommonFieldVariables(
+ map<string, string>* variables) {
+ // Note: this will be valid even though the tag emitted for packed and unpacked versions of
+ // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
+ // never effects the tag size.
+ int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
+ uint tag = internal::WireFormat::MakeTag(descriptor_);
+ uint8 tag_array[5];
+ io::CodedOutputStream::WriteTagToArray(tag, tag_array);
+ string tag_bytes = SimpleItoa(tag_array[0]);
+ for (int i = 1; i < tag_size; i++) {
+ tag_bytes += ", " + SimpleItoa(tag_array[i]);
+ }
+
+ (*variables)["access_level"] = class_access_level();
+ (*variables)["tag"] = SimpleItoa(tag);
+ (*variables)["tag_size"] = SimpleItoa(tag_size);
+ (*variables)["tag_bytes"] = tag_bytes;
+
+ (*variables)["property_name"] = property_name();
+ (*variables)["type_name"] = type_name();
+ (*variables)["name"] = name();
+ (*variables)["descriptor_name"] = descriptor_->name();
+ (*variables)["default_value"] = default_value();
+ if (has_default_value()) {
+ (*variables)["name_def_message"] =
+ (*variables)["name"] + "_ = " + (*variables)["default_value"];
+ } else {
+ (*variables)["name_def_message"] = (*variables)["name"] + "_";
+ }
+ (*variables)["capitalized_type_name"] = capitalized_type_name();
+ (*variables)["number"] = number();
+ (*variables)["has_property_check"] =
+ (*variables)["property_name"] + " != " + (*variables)["default_value"];
+ (*variables)["other_has_property_check"] = "other." +
+ (*variables)["property_name"] + " != " + (*variables)["default_value"];
+}
+
+void FieldGeneratorBase::SetCommonOneofFieldVariables(
+ map<string, string>* variables) {
+ (*variables)["oneof_name"] = oneof_name();
+ (*variables)["has_property_check"] = oneof_name() + "Case_ == " + oneof_property_name() +
+ "OneofCase." + property_name();
+ (*variables)["oneof_property_name"] = oneof_property_name();
+}
+
+FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : SourceGeneratorBase(descriptor->file()),
+ descriptor_(descriptor),
+ fieldOrdinal_(fieldOrdinal) {
+ SetCommonFieldVariables(&variables_);
+}
+
+FieldGeneratorBase::~FieldGeneratorBase() {
+}
+
+void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
+ // No-op: only message fields and repeated fields need
+ // special handling for freezing, so default to not generating any code.
+}
+
+void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
+ // No-op: expect this to be overridden by appropriate types.
+ // Could fail if we get called here though...
+}
+
+void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
+ if (descriptor_->options().deprecated())
+ {
+ printer->Print("[global::System.ObsoleteAttribute()]\n");
+ }
+}
+
+void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
+ AddDeprecatedFlag(printer);
+}
+
+std::string FieldGeneratorBase::oneof_property_name() {
+ return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true);
+}
+
+std::string FieldGeneratorBase::oneof_name() {
+ return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false);
+}
+
+std::string FieldGeneratorBase::property_name() {
+ return GetPropertyName(descriptor_);
+}
+
+std::string FieldGeneratorBase::name() {
+ return UnderscoresToCamelCase(GetFieldName(descriptor_), false);
+}
+
+std::string FieldGeneratorBase::type_name() {
+ return type_name(descriptor_);
+}
+
+std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
+ switch (descriptor->type()) {
+ case FieldDescriptor::TYPE_ENUM:
+ return GetClassName(descriptor->enum_type());
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP:
+ if (IsWrapperType(descriptor)) {
+ const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+ string wrapped_field_type_name = type_name(wrapped_field);
+ // String and ByteString go to the same type; other wrapped types go to the
+ // nullable equivalent.
+ if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
+ wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
+ return wrapped_field_type_name;
+ } else {
+ return wrapped_field_type_name + "?";
+ }
+ }
+ return GetClassName(descriptor->message_type());
+ case FieldDescriptor::TYPE_DOUBLE:
+ return "double";
+ case FieldDescriptor::TYPE_FLOAT:
+ return "float";
+ case FieldDescriptor::TYPE_INT64:
+ return "long";
+ case FieldDescriptor::TYPE_UINT64:
+ return "ulong";
+ case FieldDescriptor::TYPE_INT32:
+ return "int";
+ case FieldDescriptor::TYPE_FIXED64:
+ return "ulong";
+ case FieldDescriptor::TYPE_FIXED32:
+ return "uint";
+ case FieldDescriptor::TYPE_BOOL:
+ return "bool";
+ case FieldDescriptor::TYPE_STRING:
+ return "string";
+ case FieldDescriptor::TYPE_BYTES:
+ return "pb::ByteString";
+ case FieldDescriptor::TYPE_UINT32:
+ return "uint";
+ case FieldDescriptor::TYPE_SFIXED32:
+ return "int";
+ case FieldDescriptor::TYPE_SFIXED64:
+ return "long";
+ case FieldDescriptor::TYPE_SINT32:
+ return "int";
+ case FieldDescriptor::TYPE_SINT64:
+ return "long";
+ default:
+ GOOGLE_LOG(FATAL)<< "Unknown field type.";
+ return "";
+ }
+}
+
+bool FieldGeneratorBase::has_default_value() {
+ switch (descriptor_->type()) {
+ case FieldDescriptor::TYPE_ENUM:
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP:
+ return true;
+ case FieldDescriptor::TYPE_DOUBLE:
+ return descriptor_->default_value_double() != 0.0;
+ case FieldDescriptor::TYPE_FLOAT:
+ return descriptor_->default_value_float() != 0.0;
+ case FieldDescriptor::TYPE_INT64:
+ return descriptor_->default_value_int64() != 0L;
+ case FieldDescriptor::TYPE_UINT64:
+ return descriptor_->default_value_uint64() != 0L;
+ case FieldDescriptor::TYPE_INT32:
+ return descriptor_->default_value_int32() != 0;
+ case FieldDescriptor::TYPE_FIXED64:
+ return descriptor_->default_value_uint64() != 0L;
+ case FieldDescriptor::TYPE_FIXED32:
+ return descriptor_->default_value_uint32() != 0;
+ case FieldDescriptor::TYPE_BOOL:
+ return descriptor_->default_value_bool();
+ case FieldDescriptor::TYPE_STRING:
+ return true;
+ case FieldDescriptor::TYPE_BYTES:
+ return true;
+ case FieldDescriptor::TYPE_UINT32:
+ return descriptor_->default_value_uint32() != 0;
+ case FieldDescriptor::TYPE_SFIXED32:
+ return descriptor_->default_value_int32() != 0;
+ case FieldDescriptor::TYPE_SFIXED64:
+ return descriptor_->default_value_int64() != 0L;
+ case FieldDescriptor::TYPE_SINT32:
+ return descriptor_->default_value_int32() != 0;
+ case FieldDescriptor::TYPE_SINT64:
+ return descriptor_->default_value_int64() != 0L;
+ default:
+ GOOGLE_LOG(FATAL)<< "Unknown field type.";
+ return true;
+ }
+}
+
+bool FieldGeneratorBase::is_nullable_type() {
+ switch (descriptor_->type()) {
+ case FieldDescriptor::TYPE_ENUM:
+ case FieldDescriptor::TYPE_DOUBLE:
+ case FieldDescriptor::TYPE_FLOAT:
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_FIXED64:
+ case FieldDescriptor::TYPE_FIXED32:
+ case FieldDescriptor::TYPE_BOOL:
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_SFIXED32:
+ case FieldDescriptor::TYPE_SFIXED64:
+ case FieldDescriptor::TYPE_SINT32:
+ case FieldDescriptor::TYPE_SINT64:
+ return false;
+
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES:
+ return true;
+
+ default:
+ GOOGLE_LOG(FATAL)<< "Unknown field type.";
+ return true;
+ }
+}
+
+bool AllPrintableAscii(const std::string& text) {
+ for(int i = 0; i < text.size(); i++) {
+ if (text[i] < 0x20 || text[i] > 0x7e) {
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string FieldGeneratorBase::GetStringDefaultValueInternal() {
+ // No other default values needed for proto3...
+ return "\"\"";
+}
+
+std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
+ // No other default values needed for proto3...
+ return "pb::ByteString.Empty";
+}
+
+std::string FieldGeneratorBase::default_value() {
+ return default_value(descriptor_);
+}
+
+std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
+ switch (descriptor->type()) {
+ case FieldDescriptor::TYPE_ENUM:
+ return type_name() + "." + descriptor->default_value_enum()->name();
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP:
+ if (IsWrapperType(descriptor)) {
+ const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+ return default_value(wrapped_field);
+ } else {
+ return "null";
+ }
+ case FieldDescriptor::TYPE_DOUBLE: {
+ double value = descriptor->default_value_double();
+ if (value == numeric_limits<double>::infinity()) {
+ return "double.PositiveInfinity";
+ } else if (value == -numeric_limits<double>::infinity()) {
+ return "double.NegativeInfinity";
+ } else if (MathLimits<double>::IsNaN(value)) {
+ return "double.NaN";
+ }
+ return SimpleDtoa(value) + "D";
+ }
+ case FieldDescriptor::TYPE_FLOAT: {
+ float value = descriptor->default_value_float();
+ if (value == numeric_limits<float>::infinity()) {
+ return "float.PositiveInfinity";
+ } else if (value == -numeric_limits<float>::infinity()) {
+ return "float.NegativeInfinity";
+ } else if (MathLimits<float>::IsNaN(value)) {
+ return "float.NaN";
+ }
+ return SimpleFtoa(value) + "F";
+ }
+ case FieldDescriptor::TYPE_INT64:
+ return SimpleItoa(descriptor->default_value_int64()) + "L";
+ case FieldDescriptor::TYPE_UINT64:
+ return SimpleItoa(descriptor->default_value_uint64()) + "UL";
+ case FieldDescriptor::TYPE_INT32:
+ return SimpleItoa(descriptor->default_value_int32());
+ case FieldDescriptor::TYPE_FIXED64:
+ return SimpleItoa(descriptor->default_value_uint64()) + "UL";
+ case FieldDescriptor::TYPE_FIXED32:
+ return SimpleItoa(descriptor->default_value_uint32());
+ case FieldDescriptor::TYPE_BOOL:
+ if (descriptor->default_value_bool()) {
+ return "true";
+ } else {
+ return "false";
+ }
+ case FieldDescriptor::TYPE_STRING:
+ return GetStringDefaultValueInternal();
+ case FieldDescriptor::TYPE_BYTES:
+ return GetBytesDefaultValueInternal();
+ case FieldDescriptor::TYPE_UINT32:
+ return SimpleItoa(descriptor->default_value_uint32());
+ case FieldDescriptor::TYPE_SFIXED32:
+ return SimpleItoa(descriptor->default_value_int32());
+ case FieldDescriptor::TYPE_SFIXED64:
+ return SimpleItoa(descriptor->default_value_int64()) + "L";
+ case FieldDescriptor::TYPE_SINT32:
+ return SimpleItoa(descriptor->default_value_int32());
+ case FieldDescriptor::TYPE_SINT64:
+ return SimpleItoa(descriptor->default_value_int64()) + "L";
+ default:
+ GOOGLE_LOG(FATAL)<< "Unknown field type.";
+ return "";
+ }
+}
+
+std::string FieldGeneratorBase::number() {
+ return SimpleItoa(descriptor_->number());
+}
+
+std::string FieldGeneratorBase::capitalized_type_name() {
+ switch (descriptor_->type()) {
+ case FieldDescriptor::TYPE_ENUM:
+ return "Enum";
+ case FieldDescriptor::TYPE_MESSAGE:
+ return "Message";
+ case FieldDescriptor::TYPE_GROUP:
+ return "Group";
+ case FieldDescriptor::TYPE_DOUBLE:
+ return "Double";
+ case FieldDescriptor::TYPE_FLOAT:
+ return "Float";
+ case FieldDescriptor::TYPE_INT64:
+ return "Int64";
+ case FieldDescriptor::TYPE_UINT64:
+ return "UInt64";
+ case FieldDescriptor::TYPE_INT32:
+ return "Int32";
+ case FieldDescriptor::TYPE_FIXED64:
+ return "Fixed64";
+ case FieldDescriptor::TYPE_FIXED32:
+ return "Fixed32";
+ case FieldDescriptor::TYPE_BOOL:
+ return "Bool";
+ case FieldDescriptor::TYPE_STRING:
+ return "String";
+ case FieldDescriptor::TYPE_BYTES:
+ return "Bytes";
+ case FieldDescriptor::TYPE_UINT32:
+ return "UInt32";
+ case FieldDescriptor::TYPE_SFIXED32:
+ return "SFixed32";
+ case FieldDescriptor::TYPE_SFIXED64:
+ return "SFixed64";
+ case FieldDescriptor::TYPE_SINT32:
+ return "SInt32";
+ case FieldDescriptor::TYPE_SINT64:
+ return "SInt64";
+ default:
+ GOOGLE_LOG(FATAL)<< "Unknown field type.";
+ return "";
+ }
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h
new file mode 100644
index 00000000..d83543bd
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h
@@ -0,0 +1,103 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
+
+#include <string>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase : public SourceGeneratorBase {
+ public:
+ FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~FieldGeneratorBase();
+
+ virtual void GenerateCloningCode(io::Printer* printer) = 0;
+ virtual void GenerateFreezingCode(io::Printer* printer);
+ virtual void GenerateCodecCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer) = 0;
+ virtual void GenerateMergingCode(io::Printer* printer) = 0;
+ virtual void GenerateParsingCode(io::Printer* printer) = 0;
+ virtual void GenerateSerializationCode(io::Printer* printer) = 0;
+ virtual void GenerateSerializedSizeCode(io::Printer* printer) = 0;
+
+ virtual void WriteHash(io::Printer* printer) = 0;
+ virtual void WriteEquals(io::Printer* printer) = 0;
+ // Currently unused, as we use reflection to generate JSON
+ virtual void WriteToString(io::Printer* printer) = 0;
+
+ protected:
+ const FieldDescriptor* descriptor_;
+ const int fieldOrdinal_;
+ map<string, string> variables_;
+
+ void AddDeprecatedFlag(io::Printer* printer);
+ void AddNullCheck(io::Printer* printer);
+ void AddNullCheck(io::Printer* printer, const std::string& name);
+
+ void AddPublicMemberAttributes(io::Printer* printer);
+ void SetCommonOneofFieldVariables(map<string, string>* variables);
+
+ std::string oneof_property_name();
+ std::string oneof_name();
+ std::string property_name();
+ std::string name();
+ std::string type_name();
+ std::string type_name(const FieldDescriptor* descriptor);
+ bool has_default_value();
+ bool is_nullable_type();
+ std::string default_value();
+ std::string default_value(const FieldDescriptor* descriptor);
+ std::string number();
+ std::string capitalized_type_name();
+
+ private:
+ void SetCommonFieldVariables(map<string, string>* variables);
+ std::string GetStringDefaultValueInternal();
+ std::string GetBytesDefaultValueInternal();
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc
new file mode 100644
index 00000000..e0a6c83a
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -0,0 +1,100 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+std::string GetOutputFile(const google::protobuf::FileDescriptor* file, const std::string file_extension)
+{
+ return GetUmbrellaClassUnqualifiedName(file) + file_extension;
+}
+
+void GenerateFile(const google::protobuf::FileDescriptor* file,
+ io::Printer* printer) {
+ UmbrellaClassGenerator umbrellaGenerator(file);
+ umbrellaGenerator.Generate(printer);
+}
+
+bool Generator::Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const {
+
+ vector<pair<string, string> > options;
+ ParseGeneratorParameter(parameter, &options);
+
+ // We only support proto3 - but we make an exception for descriptor.proto.
+ if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && !IsDescriptorProto(file)) {
+ *error = "C# code generation only supports proto3 syntax";
+ return false;
+ }
+
+ std::string file_extension = ".cs";
+ for (int i = 0; i < options.size(); i++) {
+ if (options[i].first == "file_extension") {
+ file_extension = options[i].second;
+ } else {
+ *error = "Unknown generator option: " + options[i].first;
+ return false;
+ }
+ }
+
+ std::string filename = GetOutputFile(file, file_extension);
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(filename));
+ io::Printer printer(output.get(), '$');
+
+ GenerateFile(file, &printer);
+
+ return true;
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.h b/src/google/protobuf/compiler/csharp/csharp_generator.h
new file mode 100644
index 00000000..9b54e914
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.h
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class LIBPROTOC_EXPORT Generator
+ : public google::protobuf::compiler::CodeGenerator {
+ virtual bool Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const;
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
new file mode 100644
index 00000000..7ef7df42
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
@@ -0,0 +1,54 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <memory>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+namespace {
+
+// TODO(jtattermusch): add some tests.
+
+} // namespace
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
new file mode 100644
index 00000000..d25dcba9
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -0,0 +1,393 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <limits>
+#include <vector>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
+#include <google/protobuf/compiler/csharp/csharp_map_field.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+CSharpType GetCSharpType(FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32:
+ return CSHARPTYPE_INT32;
+ case FieldDescriptor::TYPE_INT64:
+ return CSHARPTYPE_INT64;
+ case FieldDescriptor::TYPE_UINT32:
+ return CSHARPTYPE_UINT32;
+ case FieldDescriptor::TYPE_UINT64:
+ return CSHARPTYPE_UINT32;
+ case FieldDescriptor::TYPE_SINT32:
+ return CSHARPTYPE_INT32;
+ case FieldDescriptor::TYPE_SINT64:
+ return CSHARPTYPE_INT64;
+ case FieldDescriptor::TYPE_FIXED32:
+ return CSHARPTYPE_UINT32;
+ case FieldDescriptor::TYPE_FIXED64:
+ return CSHARPTYPE_UINT64;
+ case FieldDescriptor::TYPE_SFIXED32:
+ return CSHARPTYPE_INT32;
+ case FieldDescriptor::TYPE_SFIXED64:
+ return CSHARPTYPE_INT64;
+ case FieldDescriptor::TYPE_FLOAT:
+ return CSHARPTYPE_FLOAT;
+ case FieldDescriptor::TYPE_DOUBLE:
+ return CSHARPTYPE_DOUBLE;
+ case FieldDescriptor::TYPE_BOOL:
+ return CSHARPTYPE_BOOL;
+ case FieldDescriptor::TYPE_ENUM:
+ return CSHARPTYPE_ENUM;
+ case FieldDescriptor::TYPE_STRING:
+ return CSHARPTYPE_STRING;
+ case FieldDescriptor::TYPE_BYTES:
+ return CSHARPTYPE_BYTESTRING;
+ case FieldDescriptor::TYPE_GROUP:
+ return CSHARPTYPE_MESSAGE;
+ case FieldDescriptor::TYPE_MESSAGE:
+ return CSHARPTYPE_MESSAGE;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+ GOOGLE_LOG(FATAL)<< "Can't get here.";
+ return (CSharpType) -1;
+}
+
+std::string StripDotProto(const std::string& proto_file) {
+ int lastindex = proto_file.find_last_of(".");
+ return proto_file.substr(0, lastindex);
+}
+
+std::string GetFileNamespace(const FileDescriptor* descriptor) {
+ if (descriptor->options().has_csharp_namespace()) {
+ return descriptor->options().csharp_namespace();
+ }
+ return UnderscoresToCamelCase(descriptor->package(), true, true);
+}
+
+std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor) {
+ // umbrella_classname can no longer be set using message option.
+ std::string proto_file = descriptor->name();
+ int lastslash = proto_file.find_last_of("/");
+ std::string base = proto_file.substr(lastslash + 1);
+ return UnderscoresToPascalCase(StripDotProto(base));
+}
+
+std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor) {
+ // TODO(jtattermusch): reintroduce csharp_umbrella_namespace option
+ bool collision = false;
+ std::string umbrella_classname = GetUmbrellaClassUnqualifiedName(descriptor);
+ for(int i = 0; i < descriptor->message_type_count(); i++) {
+ if (descriptor->message_type(i)->name() == umbrella_classname) {
+ collision = true;
+ break;
+ }
+ }
+ for (int i = 0; i < descriptor->service_count(); i++) {
+ if (descriptor->service(i)->name() == umbrella_classname) {
+ collision = true;
+ break;
+ }
+ }
+ for (int i = 0; i < descriptor->enum_type_count(); i++) {
+ if (descriptor->enum_type(i)->name() == umbrella_classname) {
+ collision = true;
+ break;
+ }
+ }
+ return collision ? "Proto" : "";
+}
+
+// TODO(jtattermusch): can we reuse a utility function?
+std::string UnderscoresToCamelCase(const std::string& input,
+ bool cap_next_letter,
+ bool preserve_period) {
+ string result;
+ // Note: I distrust ctype.h due to locales.
+ for (int i = 0; i < input.size(); i++) {
+ if ('a' <= input[i] && input[i] <= 'z') {
+ if (cap_next_letter) {
+ result += input[i] + ('A' - 'a');
+ } else {
+ result += input[i];
+ }
+ cap_next_letter = false;
+ } else if ('A' <= input[i] && input[i] <= 'Z') {
+ if (i == 0 && !cap_next_letter) {
+ // Force first letter to lower-case unless explicitly told to
+ // capitalize it.
+ result += input[i] + ('a' - 'A');
+ } else {
+ // Capital letters after the first are left as-is.
+ result += input[i];
+ }
+ cap_next_letter = false;
+ } else if ('0' <= input[i] && input[i] <= '9') {
+ result += input[i];
+ cap_next_letter = true;
+ } else {
+ cap_next_letter = true;
+ if (input[i] == '.' && preserve_period) {
+ result += '.';
+ }
+ }
+ }
+ // Add a trailing "_" if the name should be altered.
+ if (input[input.size() - 1] == '#') {
+ result += '_';
+ }
+ return result;
+}
+
+std::string UnderscoresToPascalCase(const std::string& input) {
+ return UnderscoresToCamelCase(input, true);
+}
+
+std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
+ std::string result = GetFileNamespace(file);
+ if (result != "") {
+ result += '.';
+ }
+ string classname;
+ if (file->package().empty()) {
+ classname = name;
+ } else {
+ // Strip the proto package from full_name since we've replaced it with
+ // the C# namespace.
+ classname = name.substr(file->package().size() + 1);
+ }
+ result += StringReplace(classname, ".", ".Types.", true);
+ return "global::" + result;
+}
+
+std::string GetUmbrellaClassName(const FileDescriptor* descriptor) {
+ std::string result = GetFileNamespace(descriptor);
+ if (!result.empty()) {
+ result += '.';
+ }
+ std::string umbrellaNamespace = GetUmbrellaClassNestedNamespace(descriptor);
+ if (!umbrellaNamespace.empty()) {
+ result += umbrellaNamespace + ".";
+ }
+ result += GetUmbrellaClassUnqualifiedName(descriptor);
+ return "global::" + result;
+}
+
+std::string GetClassName(const Descriptor* descriptor) {
+ return ToCSharpName(descriptor->full_name(), descriptor->file());
+}
+
+std::string GetClassName(const EnumDescriptor* descriptor) {
+ return ToCSharpName(descriptor->full_name(), descriptor->file());
+}
+
+// Groups are hacky: The name of the field is just the lower-cased name
+// of the group type. In C#, though, we would like to retain the original
+// capitalization of the type name.
+std::string GetFieldName(const FieldDescriptor* descriptor) {
+ if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
+ return descriptor->message_type()->name();
+ } else {
+ return descriptor->name();
+ }
+}
+
+std::string GetFieldConstantName(const FieldDescriptor* field) {
+ return GetPropertyName(field) + "FieldNumber";
+}
+
+std::string GetPropertyName(const FieldDescriptor* descriptor) {
+ // TODO(jtattermusch): consider introducing csharp_property_name field option
+ std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor));
+ // Avoid either our own type name or reserved names. Note that not all names
+ // are reserved - a field called to_string, write_to etc would still cause a problem.
+ // There are various ways of ending up with naming collisions, but we try to avoid obvious
+ // ones.
+ if (property_name == descriptor->containing_type()->name()
+ || property_name == "Types"
+ || property_name == "Descriptor") {
+ property_name += "_";
+ }
+ return property_name;
+}
+
+// TODO: c&p from Java protoc plugin
+// For encodings with fixed sizes, returns that size in bytes. Otherwise
+// returns -1.
+int GetFixedSize(FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return -1;
+ case FieldDescriptor::TYPE_INT64 : return -1;
+ case FieldDescriptor::TYPE_UINT32 : return -1;
+ case FieldDescriptor::TYPE_UINT64 : return -1;
+ case FieldDescriptor::TYPE_SINT32 : return -1;
+ case FieldDescriptor::TYPE_SINT64 : return -1;
+ case FieldDescriptor::TYPE_FIXED32 : return internal::WireFormatLite::kFixed32Size;
+ case FieldDescriptor::TYPE_FIXED64 : return internal::WireFormatLite::kFixed64Size;
+ case FieldDescriptor::TYPE_SFIXED32: return internal::WireFormatLite::kSFixed32Size;
+ case FieldDescriptor::TYPE_SFIXED64: return internal::WireFormatLite::kSFixed64Size;
+ case FieldDescriptor::TYPE_FLOAT : return internal::WireFormatLite::kFloatSize;
+ case FieldDescriptor::TYPE_DOUBLE : return internal::WireFormatLite::kDoubleSize;
+
+ case FieldDescriptor::TYPE_BOOL : return internal::WireFormatLite::kBoolSize;
+ case FieldDescriptor::TYPE_ENUM : return -1;
+
+ case FieldDescriptor::TYPE_STRING : return -1;
+ case FieldDescriptor::TYPE_BYTES : return -1;
+ case FieldDescriptor::TYPE_GROUP : return -1;
+ case FieldDescriptor::TYPE_MESSAGE : return -1;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return -1;
+}
+
+static const char base64_chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+std::string StringToBase64(const std::string& input) {
+ std::string result;
+ size_t remaining = input.size();
+ const unsigned char *src = (const unsigned char*) input.c_str();
+ while (remaining > 2) {
+ result += base64_chars[src[0] >> 2];
+ result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];
+ result += base64_chars[((src[1] & 0xf) << 2) | (src[2] >> 6)];
+ result += base64_chars[src[2] & 0x3f];
+ remaining -= 3;
+ src += 3;
+ }
+ switch (remaining) {
+ case 2:
+ result += base64_chars[src[0] >> 2];
+ result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];
+ result += base64_chars[(src[1] & 0xf) << 2];
+ result += '=';
+ src += 2;
+ break;
+ case 1:
+ result += base64_chars[src[0] >> 2];
+ result += base64_chars[((src[0] & 0x3) << 4)];
+ result += '=';
+ result += '=';
+ src += 1;
+ break;
+ }
+ return result;
+}
+
+std::string FileDescriptorToBase64(const FileDescriptor* descriptor) {
+ std::string fdp_bytes;
+ FileDescriptorProto fdp;
+ descriptor->CopyTo(&fdp);
+ fdp.SerializeToString(&fdp_bytes);
+ return StringToBase64(fdp_bytes);
+}
+
+FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal) {
+ switch (descriptor->type()) {
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_MESSAGE:
+ if (descriptor->is_repeated()) {
+ if (descriptor->is_map()) {
+ return new MapFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal);
+ }
+ } else {
+ if (IsWrapperType(descriptor)) {
+ if (descriptor->containing_oneof()) {
+ return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ return new WrapperFieldGenerator(descriptor, fieldOrdinal);
+ }
+ } else {
+ if (descriptor->containing_oneof()) {
+ return new MessageOneofFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ return new MessageFieldGenerator(descriptor, fieldOrdinal);
+ }
+ }
+ }
+ case FieldDescriptor::TYPE_ENUM:
+ if (descriptor->is_repeated()) {
+ return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ if (descriptor->containing_oneof()) {
+ return new EnumOneofFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ return new EnumFieldGenerator(descriptor, fieldOrdinal);
+ }
+ }
+ default:
+ if (descriptor->is_repeated()) {
+ return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ if (descriptor->containing_oneof()) {
+ return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal);
+ } else {
+ return new PrimitiveFieldGenerator(descriptor, fieldOrdinal);
+ }
+ }
+ }
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h
new file mode 100644
index 00000000..1d17af61
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -0,0 +1,132 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
+
+#include <string>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase;
+
+// TODO: start using this enum.
+enum CSharpType {
+ CSHARPTYPE_INT32 = 1,
+ CSHARPTYPE_INT64 = 2,
+ CSHARPTYPE_UINT32 = 3,
+ CSHARPTYPE_UINT64 = 4,
+ CSHARPTYPE_FLOAT = 5,
+ CSHARPTYPE_DOUBLE = 6,
+ CSHARPTYPE_BOOL = 7,
+ CSHARPTYPE_STRING = 8,
+ CSHARPTYPE_BYTESTRING = 9,
+ CSHARPTYPE_MESSAGE = 10,
+ CSHARPTYPE_ENUM = 11,
+ MAX_CSHARPTYPE = 11
+};
+
+// Converts field type to corresponding C# type.
+CSharpType GetCSharpType(FieldDescriptor::Type type);
+
+std::string StripDotProto(const std::string& proto_file);
+
+// Gets unqualified name of the umbrella class
+std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor);
+
+// Gets name of the nested for umbrella class (just the nested part,
+// not including the GetFileNamespace part).
+std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor);
+
+std::string GetClassName(const Descriptor* descriptor);
+
+std::string GetClassName(const EnumDescriptor* descriptor);
+
+std::string GetFieldName(const FieldDescriptor* descriptor);
+
+std::string GetFieldConstantName(const FieldDescriptor* field);
+
+std::string GetPropertyName(const FieldDescriptor* descriptor);
+
+int GetFixedSize(FieldDescriptor::Type type);
+
+std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter, bool preserve_period);
+
+inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
+ return UnderscoresToCamelCase(input, cap_next_letter, false);
+}
+
+std::string UnderscoresToPascalCase(const std::string& input);
+
+// TODO(jtattermusch): perhaps we could move this to strutil
+std::string StringToBase64(const std::string& input);
+
+std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
+
+uint FixedMakeTag(const FieldDescriptor* descriptor);
+
+FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+
+// Determines whether the given message is a map entry message, i.e. one implicitly created
+// by protoc due to a map<key, value> field.
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+ return descriptor->options().map_entry();
+}
+
+// Determines whether we're generating code for the proto representation of descriptors etc,
+// for use in the runtime. This is the only type which is allowed to use proto2 syntax,
+// and it generates internal classes.
+inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
+ // TODO: Do this better! (Currently this depends on a hack in generate_protos.sh to rename
+ // the file...)
+ return descriptor->name() == "google/protobuf/descriptor_proto_file.proto";
+}
+
+inline bool IsWrapperType(const FieldDescriptor* descriptor) {
+ return descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
+ descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
new file mode 100644
index 00000000..f84ad6f7
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -0,0 +1,137 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_map_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+MapFieldGenerator::~MapFieldGenerator() {
+}
+
+void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
+ const FieldDescriptor* key_descriptor =
+ descriptor_->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor_->message_type()->FindFieldByName("value");
+ variables_["key_type_name"] = type_name(key_descriptor);
+ variables_["value_type_name"] = type_name(value_descriptor);
+ variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : "";
+ scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));
+ scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
+
+ printer->Print(
+ variables_,
+ "private static readonly pbc::MapField<$key_type_name$, $value_type_name$>.Codec _map_$name$_codec\n"
+ " = new pbc::MapField<$key_type_name$, $value_type_name$>.Codec(");
+ key_generator->GenerateCodecCode(printer);
+ printer->Print(", ");
+ value_generator->GenerateCodecCode(printer);
+ printer->Print(
+ variables_,
+ ", $tag$);\n"
+ "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
+ " get { return $name$_; }\n"
+ "}\n");
+}
+
+void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.Add(other.$name$_);\n");
+}
+
+void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.AddEntriesFrom(input, _map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.WriteTo(output, _map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "size += $name$_.CalculateSize(_map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "hash ^= $property_name$.GetHashCode();\n");
+}
+void MapFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if (!$property_name$.Equals(other.$property_name$)) return false;\n");
+}
+
+void MapFieldGenerator::WriteToString(io::Printer* printer) {
+ // TODO: If we ever actually use ToString, we'll need to impleme this...
+}
+
+void MapFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$name$_ = other.$name$_.Clone();\n");
+}
+
+void MapFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.h b/src/google/protobuf/compiler/csharp/csharp_map_field.h
new file mode 100644
index 00000000..f33fe1c3
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.h
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class MapFieldGenerator : public FieldGeneratorBase {
+ public:
+ MapFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~MapFieldGenerator();
+
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateFreezingCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
new file mode 100644
index 00000000..a71a7909
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -0,0 +1,482 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+#include <algorithm>
+#include <map>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
+ return d1->number() < d2->number();
+}
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor)
+ : SourceGeneratorBase(descriptor->file()),
+ descriptor_(descriptor) {
+
+ // sorted field names
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_names_.push_back(descriptor_->field(i)->name());
+ }
+ std::sort(field_names_.begin(), field_names_.end());
+
+ // fields by number
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ fields_by_number_.push_back(descriptor_->field(i));
+ }
+ std::sort(fields_by_number_.begin(), fields_by_number_.end(),
+ CompareFieldNumbers);
+}
+
+MessageGenerator::~MessageGenerator() {
+}
+
+std::string MessageGenerator::class_name() {
+ return descriptor_->name();
+}
+
+std::string MessageGenerator::full_class_name() {
+ return GetClassName(descriptor_);
+}
+
+const std::vector<std::string>& MessageGenerator::field_names() {
+ return field_names_;
+}
+
+const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
+ return fields_by_number_;
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+ map<string, string> vars;
+ vars["class_name"] = class_name();
+ vars["access_level"] = class_access_level();
+
+ printer->Print(
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+ WriteGeneratedCodeAttributes(printer);
+ printer->Print(
+ vars,
+ "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n");
+ printer->Indent();
+
+ // All static fields and properties
+ printer->Print(
+ vars,
+ "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n"
+ "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n");
+
+ // Access the message descriptor via the relevant file descriptor or containing message descriptor.
+ if (!descriptor_->containing_type()) {
+ vars["descriptor_accessor"] = GetUmbrellaClassName(descriptor_->file())
+ + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
+ } else {
+ vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
+ + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]";
+ }
+
+ printer->Print(
+ vars,
+ "public static pbr::MessageDescriptor Descriptor {\n"
+ " get { return $descriptor_accessor$; }\n"
+ "}\n"
+ "\n"
+ "pbr::MessageDescriptor pb::IMessage.Descriptor {\n"
+ " get { return Descriptor; }\n"
+ "}\n"
+ "\n");
+
+ // Parameterless constructor and partial OnConstruction method.
+ printer->Print(
+ vars,
+ "public $class_name$() {\n"
+ " OnConstruction();\n"
+ "}\n\n"
+ "partial void OnConstruction();\n\n");
+
+ GenerateCloningCode(printer);
+ GenerateFreezingCode(printer);
+
+ // Fields/properties
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+
+ // Rats: we lose the debug comment here :(
+ printer->Print(
+ "public const int $field_constant_name$ = $index$;\n",
+ "field_constant_name", GetFieldConstantName(fieldDescriptor),
+ "index", SimpleItoa(fieldDescriptor->number()));
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(fieldDescriptor));
+ generator->GenerateMembers(printer);
+ printer->Print("\n");
+ }
+
+ // oneof properties
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
+ vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
+ vars["original_name"] = descriptor_->oneof_decl(i)->name();
+ printer->Print(
+ vars,
+ "private object $name$_;\n"
+ "public enum $property_name$OneofCase {\n");
+ printer->Indent();
+ printer->Print("None = 0,\n");
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print("$field_property_name$ = $index$,\n",
+ "field_property_name", GetPropertyName(field),
+ "index", SimpleItoa(field->number()));
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(
+ vars,
+ "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n"
+ "public $property_name$OneofCase $property_name$Case {\n"
+ " get { return $name$Case_; }\n"
+ "}\n\n"
+ "public void Clear$property_name$() {\n"
+ " $name$Case_ = $property_name$OneofCase.None;\n"
+ " $name$_ = null;\n"
+ "}\n\n");
+ }
+
+ // Standard methods
+ GenerateFrameworkMethods(printer);
+ GenerateMessageSerializationMethods(printer);
+ GenerateMergingMethods(printer);
+
+ // Nested messages and enums
+ if (HasNestedGeneratedTypes()) {
+ printer->Print("#region Nested types\n"
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+ WriteGeneratedCodeAttributes(printer);
+ printer->Print("public static partial class Types {\n");
+ printer->Indent();
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ EnumGenerator enumGenerator(descriptor_->enum_type(i));
+ enumGenerator.Generate(printer);
+ }
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // Don't generate nested types for maps...
+ if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
+ MessageGenerator messageGenerator(descriptor_->nested_type(i));
+ messageGenerator.Generate(printer);
+ }
+ }
+ printer->Outdent();
+ printer->Print("}\n"
+ "#endregion\n"
+ "\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print("\n");
+}
+
+// Helper to work out whether we need to generate a class to hold nested types/enums.
+// Only tricky because we don't want to generate map entry types.
+bool MessageGenerator::HasNestedGeneratedTypes()
+{
+ if (descriptor_->enum_type_count() > 0) {
+ return true;
+ }
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
+ map<string, string> vars;
+ vars["class_name"] = class_name();
+ printer->Print(
+ vars,
+ "public $class_name$($class_name$ other) : this() {\n");
+ printer->Indent();
+ // Clone non-oneof fields first
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->GenerateCloningCode(printer);
+ }
+ }
+ // Clone just the right field for each oneof
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+ vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
+ vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
+ printer->Print(vars, "switch (other.$property_name$Case) {\n");
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
+ vars["field_property_name"] = GetPropertyName(field);
+ printer->Print(
+ vars,
+ "case $property_name$OneofCase.$field_property_name$:\n");
+ printer->Indent();
+ generator->GenerateCloningCode(printer);
+ printer->Print("break;\n");
+ printer->Outdent();
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ printer->Print(
+ vars,
+ "public $class_name$ Clone() {\n"
+ " return new $class_name$(this);\n"
+ "}\n\n");
+}
+
+void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
+ map<string, string> vars;
+ vars["class_name"] = class_name();
+
+ // Equality
+ printer->Print(
+ vars,
+ "public override bool Equals(object other) {\n"
+ " return Equals(other as $class_name$);\n"
+ "}\n\n"
+ "public bool Equals($class_name$ other) {\n"
+ " if (ReferenceEquals(other, null)) {\n"
+ " return false;\n"
+ " }\n"
+ " if (ReferenceEquals(other, this)) {\n"
+ " return true;\n"
+ " }\n");
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->WriteEquals(printer);
+ }
+ printer->Outdent();
+ printer->Print(
+ " return true;\n"
+ "}\n\n");
+
+ // GetHashCode
+ // Start with a non-zero value to easily distinguish between null and "empty" messages.
+ printer->Print(
+ "public override int GetHashCode() {\n"
+ " int hash = 1;\n");
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->WriteHash(printer);
+ }
+ printer->Print("return hash;\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ printer->Print(
+ "public override string ToString() {\n"
+ " return pb::JsonFormatter.Default.Format(this);\n"
+ "}\n\n");
+}
+
+void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
+ printer->Print(
+ "public void WriteTo(pb::CodedOutputStream output) {\n");
+ printer->Indent();
+
+ // Serialize all the fields
+ for (int i = 0; i < fields_by_number().size(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(fields_by_number()[i]));
+ generator->GenerateSerializationCode(printer);
+ }
+
+ // TODO(jonskeet): Memoize size of frozen messages?
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n"
+ "public int CalculateSize() {\n");
+ printer->Indent();
+ printer->Print("int size = 0;\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->GenerateSerializedSizeCode(printer);
+ }
+ printer->Print("return size;\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+ map<string, string> vars;
+ vars["class_name"] = class_name();
+
+ printer->Print(
+ vars,
+ "public void MergeFrom($class_name$ other) {\n");
+ printer->Indent();
+ printer->Print(
+ "if (other == null) {\n"
+ " return;\n"
+ "}\n");
+ // Merge non-oneof fields
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->GenerateMergingCode(printer);
+ }
+ }
+ // Merge oneof fields
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+ vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
+ vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
+ printer->Print(vars, "switch (other.$property_name$Case) {\n");
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ vars["field_property_name"] = GetPropertyName(field);
+ printer->Print(
+ vars,
+ "case $property_name$OneofCase.$field_property_name$:\n"
+ " $field_property_name$ = other.$field_property_name$;\n"
+ " break;\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+ printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n");
+ printer->Indent();
+ printer->Print(
+ "uint tag;\n"
+ "while ((tag = input.ReadTag()) != 0) {\n"
+ " switch(tag) {\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Print(
+ "default:\n"
+ " input.SkipLastField();\n" // We're not storing the data, but we still need to consume it.
+ " break;\n");
+ for (int i = 0; i < fields_by_number().size(); i++) {
+ const FieldDescriptor* field = fields_by_number()[i];
+ internal::WireFormatLite::WireType wt =
+ internal::WireFormat::WireTypeForFieldType(field->type());
+ uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt);
+ // Handle both packed and unpacked repeated fields with the same Read*Array call;
+ // the two generated cases are the packed and unpacked tags.
+ // TODO(jonskeet): Check that is_packable is equivalent to is_repeated && wt in { VARINT, FIXED32, FIXED64 }.
+ // It looks like it is...
+ if (field->is_packable()) {
+ printer->Print(
+ "case $packed_tag$:\n",
+ "packed_tag",
+ SimpleItoa(
+ internal::WireFormatLite::MakeTag(
+ field->number(),
+ internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
+ }
+
+ printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag));
+ printer->Indent();
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(field));
+ generator->GenerateParsingCode(printer);
+ printer->Print("break;\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n"); // switch
+ printer->Outdent();
+ printer->Print("}\n"); // while
+ printer->Outdent();
+ printer->Print("}\n\n"); // method
+}
+
+int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) {
+ for (int i = 0; i < field_names().size(); i++) {
+ if (field_names()[i] == descriptor->name()) {
+ return i;
+ }
+ }
+ GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name();
+ return -1;
+}
+
+FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
+ const FieldDescriptor* descriptor) {
+ return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor));
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h
new file mode 100644
index 00000000..f0c49ac9
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.h
@@ -0,0 +1,89 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase;
+
+class MessageGenerator : public SourceGeneratorBase {
+ public:
+ MessageGenerator(const Descriptor* descriptor);
+ ~MessageGenerator();
+
+ void GenerateCloningCode(io::Printer* printer);
+ void GenerateFreezingCode(io::Printer* printer);
+ void GenerateFrameworkMethods(io::Printer* printer);
+ void Generate(io::Printer* printer);
+
+ private:
+ const Descriptor* descriptor_;
+ std::vector<std::string> field_names_;
+ std::vector<const FieldDescriptor*> fields_by_number_;
+
+ void GenerateMessageSerializationMethods(io::Printer* printer);
+ void GenerateMergingMethods(io::Printer* printer);
+
+ int GetFieldOrdinal(const FieldDescriptor* descriptor);
+ FieldGeneratorBase* CreateFieldGeneratorInternal(
+ const FieldDescriptor* descriptor);
+
+ bool HasNestedGeneratedTypes();
+
+ std::string class_name();
+ std::string full_class_name();
+
+ // field names sorted alphabetically
+ const std::vector<std::string>& field_names();
+
+ // field descriptors sorted by number
+ const std::vector<const FieldDescriptor*>& fields_by_number();
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
new file mode 100644
index 00000000..4f576cd1
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
@@ -0,0 +1,193 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+ variables_["has_property_check"] = name() + "_ != null";
+ variables_["has_not_property_check"] = name() + "_ == null";
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {
+
+}
+
+void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "private $type_name$ $name$_;\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ $type_name$ $property_name$ {\n"
+ " get { return $name$_; }\n"
+ " set {\n"
+ " $name$_ = value;\n"
+ " }\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if (other.$has_property_check$) {\n"
+ " if ($has_not_property_check$) {\n"
+ " $name$_ = new $type_name$();\n"
+ " }\n"
+ " $property_name$.MergeFrom(other.$property_name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_not_property_check$) {\n"
+ " $name$_ = new $type_name$();\n"
+ "}\n"
+ // TODO(jonskeet): Do we really need merging behaviour like this?
+ "input.ReadMessage($name$_);\n"); // No need to support TYPE_GROUP...
+}
+
+void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " output.WriteRawTag($tag_bytes$);\n"
+ " output.WriteMessage($property_name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($property_name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
+}
+void MessageFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if (!object.Equals($property_name$, other.$property_name$)) return false;\n");
+}
+void MessageFieldGenerator::WriteToString(io::Printer* printer) {
+ variables_["field_name"] = GetFieldName(descriptor_);
+ printer->Print(
+ variables_,
+ "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");
+}
+
+void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$property_name$ = other.$has_property_check$ ? other.$property_name$.Clone() : null;\n");
+}
+
+void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)");
+}
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : MessageFieldGenerator(descriptor, fieldOrdinal) {
+ SetCommonOneofFieldVariables(&variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {
+
+}
+
+void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ $type_name$ $property_name$ {\n"
+ " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
+ " set {\n"
+ " $oneof_name$_ = value;\n"
+ " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
+ " }\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ // TODO(jonskeet): We may be able to do better than this
+ printer->Print(
+ variables_,
+ "$type_name$ subBuilder = new $type_name$();\n"
+ "if ($has_property_check$) {\n"
+ " subBuilder.MergeFrom($property_name$);\n"
+ "}\n"
+ "input.ReadMessage(subBuilder);\n" // No support of TYPE_GROUP
+ "$property_name$ = subBuilder;\n");
+}
+
+void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
+}
+
+void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$property_name$ = other.$property_name$.Clone();\n");
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h
new file mode 100644
index 00000000..dc6e4dc5
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class MessageFieldGenerator : public FieldGeneratorBase {
+ public:
+ MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~MessageFieldGenerator();
+
+ virtual void GenerateCodecCode(io::Printer* printer);
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateFreezingCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class MessageOneofFieldGenerator : public MessageFieldGenerator {
+ public:
+ MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~MessageOneofFieldGenerator();
+
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_names.h b/src/google/protobuf/compiler/csharp/csharp_names.h
new file mode 100644
index 00000000..ccd2e720
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_names.h
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Provides a mechanism for mapping a descriptor to the
+// fully-qualified name of the corresponding C# class.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FileDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace csharp {
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The namespace to use for given file descriptor.
+string GetFileNamespace(const FileDescriptor* descriptor);
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The fully-qualified C# class name.
+string GetClassName(const Descriptor* descriptor);
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The fully-qualified name of the C# class that provides
+// access to the file descriptor. Proto compiler generates
+// such class for each .proto file processed.
+std::string GetUmbrellaClassName(const FileDescriptor* descriptor);
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
new file mode 100644
index 00000000..fc043ec0
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -0,0 +1,214 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+ // TODO(jonskeet): Make this cleaner...
+ is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING
+ && descriptor->type() != FieldDescriptor::TYPE_BYTES;
+ if (!is_value_type) {
+ variables_["has_property_check"] = variables_["property_name"] + ".Length != 0";
+ variables_["other_has_property_check"] = "other." + variables_["property_name"] + ".Length != 0";
+ }
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {
+}
+
+void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
+ // TODO(jonskeet): Work out whether we want to prevent the fields from ever being
+ // null, or whether we just handle it, in the cases of bytes and string.
+ // (Basically, should null-handling code be in the getter or the setter?)
+ printer->Print(
+ variables_,
+ "private $type_name$ $name_def_message$;\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ $type_name$ $property_name$ {\n"
+ " get { return $name$_; }\n"
+ " set {\n");
+ if (is_value_type) {
+ printer->Print(
+ variables_,
+ " $name$_ = value;\n");
+ } else {
+ printer->Print(
+ variables_,
+ " $name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n");
+ }
+ printer->Print(
+ " }\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($other_has_property_check$) {\n"
+ " $property_name$ = other.$property_name$;\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ // Note: invoke the property setter rather than writing straight to the field,
+ // so that we can normalize "null to empty" for strings and bytes.
+ printer->Print(
+ variables_,
+ "$property_name$ = input.Read$capitalized_type_name$();\n");
+}
+
+void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " output.WriteRawTag($tag_bytes$);\n"
+ " output.Write$capitalized_type_name$($property_name$);\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n");
+ printer->Indent();
+ int fixedSize = GetFixedSize(descriptor_->type());
+ if (fixedSize == -1) {
+ printer->Print(
+ variables_,
+ "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n");
+ } else {
+ printer->Print(
+ "size += $tag_size$ + $fixed_size$;\n",
+ "fixed_size", SimpleItoa(fixedSize),
+ "tag_size", variables_["tag_size"]);
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
+}
+void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($property_name$ != other.$property_name$) return false;\n");
+}
+void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
+}
+
+void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$name$_ = other.$name$_;\n");
+}
+
+void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.For$capitalized_type_name$($tag$)");
+}
+
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+ const FieldDescriptor* descriptor, int fieldOrdinal)
+ : PrimitiveFieldGenerator(descriptor, fieldOrdinal) {
+ SetCommonOneofFieldVariables(&variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ $type_name$ $property_name$ {\n"
+ " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
+ " set {\n");
+ if (is_value_type) {
+ printer->Print(
+ variables_,
+ " $oneof_name$_ = value;\n");
+ } else {
+ printer->Print(
+ variables_,
+ " $oneof_name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n");
+ }
+ printer->Print(
+ variables_,
+ " $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"
+ " }\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
+ printer->Print(variables_,
+ "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$property_name$ = input.Read$capitalized_type_name$();\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$property_name$ = other.$property_name$;\n");
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
new file mode 100644
index 00000000..8b87ebc4
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
@@ -0,0 +1,88 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class PrimitiveFieldGenerator : public FieldGeneratorBase {
+ public:
+ PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~PrimitiveFieldGenerator();
+
+ virtual void GenerateCodecCode(io::Printer* printer);
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ protected:
+ bool is_value_type;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+ PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~PrimitiveOneofFieldGenerator();
+
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
new file mode 100644
index 00000000..625631df
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
@@ -0,0 +1,125 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
+ const FieldDescriptor* descriptor, int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {
+
+}
+
+void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+ " = pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x);\n");
+ printer->Print(variables_,
+ "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
+ " get { return $name$_; }\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.Add(other.$name$_);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.WriteTo(output, _repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "size += $name$_.CalculateSize(_repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "hash ^= $name$_.GetHashCode();\n");
+}
+
+void RepeatedEnumFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if(!$name$_.Equals(other.$name$_)) return false;\n");
+}
+
+void RepeatedEnumFieldGenerator::WriteToString(io::Printer* printer) {
+ printer->Print(variables_,
+ "PrintField(\"$descriptor_name$\", $name$_, writer);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$name$_ = other.$name$_.Clone();\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h
new file mode 100644
index 00000000..ee50eef0
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// TODO(jonskeet): Refactor repeated field support; all the implementations are *really* similar. We
+// should probably have a RepeatedFieldGeneratorBase.
+class RepeatedEnumFieldGenerator : public FieldGeneratorBase {
+ public:
+ RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~RepeatedEnumFieldGenerator();
+
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateFreezingCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
new file mode 100644
index 00000000..7fbab681
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -0,0 +1,140 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+ const FieldDescriptor* descriptor, int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {
+
+}
+
+void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+ " = ");
+ // Don't want to duplicate the codec code here... maybe we should have a
+ // "create single field generator for this repeated field"
+ // function, but it doesn't seem worth it for just this.
+ if (IsWrapperType(descriptor_)) {
+ scoped_ptr<FieldGeneratorBase> single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_));
+ single_generator->GenerateCodecCode(printer);
+ } else {
+ scoped_ptr<FieldGeneratorBase> single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_));
+ single_generator->GenerateCodecCode(printer);
+ }
+ printer->Print(";\n");
+ printer->Print(
+ variables_,
+ "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
+ " get { return $name$_; }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.Add(other.$name$_);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.WriteTo(output, _repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "size += $name$_.CalculateSize(_repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "hash ^= $name$_.GetHashCode();\n");
+}
+
+void RepeatedMessageFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if(!$name$_.Equals(other.$name$_)) return false;\n");
+}
+
+void RepeatedMessageFieldGenerator::WriteToString(io::Printer* printer) {
+ variables_["field_name"] = GetFieldName(descriptor_);
+ printer->Print(
+ variables_,
+ "PrintField(\"$field_name$\", $name$_, writer);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$name$_ = other.$name$_.Clone();\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h
new file mode 100644
index 00000000..cf601c7e
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class RepeatedMessageFieldGenerator : public FieldGeneratorBase {
+ public:
+ RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~RepeatedMessageFieldGenerator();
+
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateFreezingCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
new file mode 100644
index 00000000..1163ce73
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
@@ -0,0 +1,123 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {
+
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+ " = pb::FieldCodec.For$capitalized_type_name$($tag$);\n");
+ printer->Print(variables_,
+ "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
+ " get { return $name$_; }\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.Add(other.$name$_);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$name$_.WriteTo(output, _repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "size += $name$_.CalculateSize(_repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "hash ^= $name$_.GetHashCode();\n");
+}
+void RepeatedPrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if(!$name$_.Equals(other.$name$_)) return false;\n");
+}
+void RepeatedPrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
+ printer->Print(variables_,
+ "PrintField(\"$descriptor_name$\", $name$_, writer);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$name$_ = other.$name$_.Clone();\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h
new file mode 100644
index 00000000..f1ceeb50
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase {
+ public:
+ RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~RepeatedPrimitiveFieldGenerator();
+
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateFreezingCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
new file mode 100644
index 00000000..735d164a
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
@@ -0,0 +1,66 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor)
+ : descriptor_(descriptor) {
+}
+
+SourceGeneratorBase::~SourceGeneratorBase() {
+}
+
+void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) {
+ // This hook can be used to reintroduce generated code attributes in the future.
+}
+
+std::string SourceGeneratorBase::class_access_level() {
+ return IsDescriptorProto(descriptor_) ? "internal" : "public"; // public_classes is always on.
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
new file mode 100644
index 00000000..6caef171
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class SourceGeneratorBase {
+ protected:
+ SourceGeneratorBase(const FileDescriptor* descriptor);
+ virtual ~SourceGeneratorBase();
+
+ std::string class_access_level();
+
+ void WriteGeneratedCodeAttributes(io::Printer* printer);
+
+ private:
+ const FileDescriptor* descriptor_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceGeneratorBase);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
new file mode 100644
index 00000000..0ffae3d4
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
@@ -0,0 +1,295 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+UmbrellaClassGenerator::UmbrellaClassGenerator(const FileDescriptor* file)
+ : SourceGeneratorBase(file),
+ file_(file) {
+ namespace_ = GetFileNamespace(file);
+ umbrellaClassname_ = GetUmbrellaClassUnqualifiedName(file);
+ umbrellaNamespace_ = GetUmbrellaClassNestedNamespace(file);
+}
+
+UmbrellaClassGenerator::~UmbrellaClassGenerator() {
+}
+
+void UmbrellaClassGenerator::Generate(io::Printer* printer) {
+ WriteIntroduction(printer);
+
+ WriteDescriptor(printer);
+ // Close the class declaration.
+ printer->Outdent();
+ printer->Print("}\n");
+
+ // Close the namespace around the umbrella class if defined
+ if (!umbrellaNamespace_.empty()) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
+ // write children: Enums
+ if (file_->enum_type_count() > 0) {
+ printer->Print("#region Enums\n");
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ EnumGenerator enumGenerator(file_->enum_type(i));
+ enumGenerator.Generate(printer);
+ }
+ printer->Print("#endregion\n");
+ printer->Print("\n");
+ }
+
+ // write children: Messages
+ if (file_->message_type_count() > 0) {
+ printer->Print("#region Messages\n");
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ MessageGenerator messageGenerator(file_->message_type(i));
+ messageGenerator.Generate(printer);
+ }
+ printer->Print("#endregion\n");
+ printer->Print("\n");
+ }
+
+ // TODO(jtattermusch): add insertion point for services.
+
+ if (!namespace_.empty()) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Print("\n");
+ printer->Print("#endregion Designer generated code\n");
+}
+
+void UmbrellaClassGenerator::WriteIntroduction(io::Printer* printer) {
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $file_name$\n"
+ "#pragma warning disable 1591, 0612, 3021\n"
+ "#region Designer generated code\n"
+ "\n"
+ "using pb = global::Google.Protobuf;\n"
+ "using pbc = global::Google.Protobuf.Collections;\n"
+ "using pbr = global::Google.Protobuf.Reflection;\n"
+ "using scg = global::System.Collections.Generic;\n",
+ "file_name", file_->name());
+
+ if (!namespace_.empty()) {
+ printer->Print("namespace $namespace$ {\n", "namespace", namespace_);
+ printer->Indent();
+ printer->Print("\n");
+ }
+
+ // Add the namespace around the umbrella class if defined
+ if (!umbrellaNamespace_.empty()) {
+ printer->Print("namespace $umbrella_namespace$ {\n",
+ "umbrella_namespace", umbrellaNamespace_);
+ printer->Indent();
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+ WriteGeneratedCodeAttributes(printer);
+ printer->Print(
+ "$access_level$ static partial class $umbrella_class_name$ {\n"
+ "\n",
+ "access_level", class_access_level(),
+ "umbrella_class_name", umbrellaClassname_);
+ printer->Indent();
+}
+
+void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
+ printer->Print(
+ "#region Descriptor\n"
+ "public static pbr::FileDescriptor Descriptor {\n"
+ " get { return descriptor; }\n"
+ "}\n"
+ "private static pbr::FileDescriptor descriptor;\n"
+ "\n"
+ "static $umbrella_class_name$() {\n",
+ "umbrella_class_name", umbrellaClassname_);
+ printer->Indent();
+ printer->Print(
+ "byte[] descriptorData = global::System.Convert.FromBase64String(\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Print("string.Concat(\n");
+ printer->Indent();
+
+ // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64.
+ std::string base64 = FileDescriptorToBase64(file_);
+ while (base64.size() > 60) {
+ printer->Print("\"$base64$\", \n", "base64", base64.substr(0, 60));
+ base64 = base64.substr(60);
+ }
+ printer->Print("\"$base64$\"));\n", "base64", base64);
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+
+ // -----------------------------------------------------------------
+ // Invoke InternalBuildGeneratedFileFrom() to build the file.
+ printer->Print(
+ "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
+ printer->Print(" new pbr::FileDescriptor[] { ");
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ printer->Print(
+ "$full_umbrella_class_name$.Descriptor, ",
+ "full_umbrella_class_name",
+ GetUmbrellaClassName(file_->dependency(i)));
+ }
+ printer->Print("},\n"
+ " new pbr::GeneratedCodeInfo(");
+ // Specify all the generated code information, recursively.
+ if (file_->enum_type_count() > 0) {
+ printer->Print("new[] {");
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ printer->Print("typeof($type_name$), ", "type_name", GetClassName(file_->enum_type(i)));
+ }
+ printer->Print("}, ");
+ }
+ else {
+ printer->Print("null, ");
+ }
+ if (file_->message_type_count() > 0) {
+ printer->Print("new pbr::GeneratedCodeInfo[] {\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ WriteGeneratedCodeInfo(file_->message_type(i), printer, i == file_->message_type_count() - 1);
+ }
+ printer->Outdent();
+ printer->Print("\n}));\n");
+ printer->Outdent();
+ printer->Outdent();
+ }
+ else {
+ printer->Print("null));\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print("#endregion\n\n");
+}
+
+// Write out the generated code for a particular message. This consists of the CLR type, property names
+// corresponding to fields, names corresponding to oneofs, nested enums, and nested types. Each array part
+// can be specified as null if it would be empty, to make the generated code somewhat simpler to read.
+// We write a line break at the end of each generated code info, so that in the final file we'll see all
+// the types, pre-ordered depth first, one per line. The indentation will be slightly unusual,
+// in that it will look like a single array when it's actually constructing a tree, but it'll be easy to
+// read even with multiple levels of nesting.
+// The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate
+// context. It governs whether or not a trailing comma and newline is written after the constructor, effectively
+// just controlling the formatting in the generated code.
+void UmbrellaClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
+ if (IsMapEntryMessage(descriptor)) {
+ printer->Print("null, ");
+ return;
+ }
+ // Generated message type
+ printer->Print("new pbr::GeneratedCodeInfo(typeof($type_name$), ", "type_name", GetClassName(descriptor));
+
+ // Fields
+ if (descriptor->field_count() > 0) {
+ std::vector<std::string> fields;
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields.push_back(GetPropertyName(descriptor->field(i)));
+ }
+ printer->Print("new[]{ \"$fields$\" }, ", "fields", JoinStrings(fields, "\", \""));
+ }
+ else {
+ printer->Print("null, ");
+ }
+
+ // Oneofs
+ if (descriptor->oneof_decl_count() > 0) {
+ std::vector<std::string> oneofs;
+ for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
+ oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true));
+ }
+ printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", JoinStrings(oneofs, "\", \""));
+ }
+ else {
+ printer->Print("null, ");
+ }
+
+ // Nested enums
+ if (descriptor->enum_type_count() > 0) {
+ std::vector<std::string> enums;
+ for (int i = 0; i < descriptor->enum_type_count(); i++) {
+ enums.push_back(GetClassName(descriptor->enum_type(i)));
+ }
+ printer->Print("new[]{ typeof($enums$) }, ", "enums", JoinStrings(enums, "), typeof("));
+ }
+ else {
+ printer->Print("null, ");
+ }
+
+ // Nested types
+ if (descriptor->nested_type_count() > 0) {
+ // Need to specify array type explicitly here, as all elements may be null.
+ printer->Print("new pbr::GeneratedCodeInfo[] { ");
+ for (int i = 0; i < descriptor->nested_type_count(); i++) {
+ WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1);
+ }
+ printer->Print("}");
+ }
+ else {
+ printer->Print("null");
+ }
+ printer->Print(last ? ")" : "),\n");
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h
new file mode 100644
index 00000000..b8bd2133
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class UmbrellaClassGenerator : public SourceGeneratorBase {
+ public:
+ UmbrellaClassGenerator(const FileDescriptor* file);
+ ~UmbrellaClassGenerator();
+
+ void Generate(io::Printer* printer);
+
+ private:
+ const FileDescriptor* file_;
+
+ std::string namespace_;
+ std::string umbrellaClassname_;
+ std::string umbrellaNamespace_;
+
+ void WriteIntroduction(io::Printer* printer);
+ void WriteDescriptor(io::Printer* printer);
+ void WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
new file mode 100644
index 00000000..44f832bf
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -0,0 +1,207 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : FieldGeneratorBase(descriptor, fieldOrdinal) {
+ variables_["has_property_check"] = name() + "_ != null";
+ variables_["has_not_property_check"] = name() + "_ == null";
+ const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+ is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
+ wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
+ if (is_value_type) {
+ variables_["nonnullable_type_name"] = type_name(wrapped_field);
+ }
+}
+
+WrapperFieldGenerator::~WrapperFieldGenerator() {
+}
+
+void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
+ GenerateCodecCode(printer);
+ printer->Print(
+ variables_,
+ ";\n"
+ "private $type_name$ $name$_;\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ $type_name$ $property_name$ {\n"
+ " get { return $name$_; }\n"
+ " set {\n"
+ " $name$_ = value;\n"
+ " }\n"
+ "}\n");
+}
+
+void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if (other.$has_property_check$) {\n"
+ " if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n"
+ " $property_name$ = other.$property_name$;\n"
+ " }\n"
+ "}\n");
+}
+
+void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$type_name$ value = _single_$name$_codec.Read(input);\n"
+ "if ($has_not_property_check$ || value != $default_value$) {\n"
+ " $property_name$ = value;\n"
+ "}\n");
+}
+
+void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
+ "}\n");
+}
+
+void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
+ "}\n");
+}
+
+void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
+}
+
+void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "if ($property_name$ != other.$property_name$) return false;\n");
+}
+
+void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
+ // TODO: Implement if we ever actually need it...
+}
+
+void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+ printer->Print(variables_,
+ "$property_name$ = other.$property_name$;\n");
+}
+
+void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+ if (is_value_type) {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
+ } else {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
+ }
+}
+
+WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int fieldOrdinal)
+ : WrapperFieldGenerator(descriptor, fieldOrdinal) {
+ SetCommonOneofFieldVariables(&variables_);
+}
+
+WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
+}
+
+void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+ // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
+ GenerateCodecCode(printer);
+ printer->Print(";\n");
+ AddDeprecatedFlag(printer);
+ printer->Print(
+ variables_,
+ "$access_level$ $type_name$ $property_name$ {\n"
+ " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
+ " set {\n"
+ " $oneof_name$_ = value;\n"
+ " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
+ " }\n"
+ "}\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$property_name$ = _oneof_$name$_codec.Read(input);\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ // TODO: I suspect this is wrong...
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
+ "}\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ // TODO: I suspect this is wrong...
+ printer->Print(
+ variables_,
+ "if ($has_property_check$) {\n"
+ " size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
+ "}\n");
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
new file mode 100644
index 00000000..6e2414af
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
@@ -0,0 +1,85 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class WrapperFieldGenerator : public FieldGeneratorBase {
+ public:
+ WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~WrapperFieldGenerator();
+
+ virtual void GenerateCodecCode(io::Printer* printer);
+ virtual void GenerateCloningCode(io::Printer* printer);
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateMergingCode(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ virtual void WriteHash(io::Printer* printer);
+ virtual void WriteEquals(io::Printer* printer);
+ virtual void WriteToString(io::Printer* printer);
+
+ private:
+ bool is_value_type; // True for int32 etc; false for bytes and string
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WrapperFieldGenerator);
+};
+
+class WrapperOneofFieldGenerator : public WrapperFieldGenerator {
+ public:
+ WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+ ~WrapperOneofFieldGenerator();
+
+ virtual void GenerateMembers(io::Printer* printer);
+ virtual void GenerateParsingCode(io::Printer* printer);
+ virtual void GenerateSerializationCode(io::Printer* printer);
+ virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WrapperOneofFieldGenerator);
+};
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 71a2ba4b..39318a19 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -67,7 +67,13 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
(*variables)["default_number"] = SimpleItoa(
descriptor->default_value_enum()->number());
- (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+ if (descriptor->is_packed()) {
+ (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag(
+ descriptor->number(),
+ internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+ } else {
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+ }
(*variables)["tag_size"] = SimpleItoa(
internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
@@ -641,7 +647,7 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
}
- if (descriptor_->options().packed() &&
+ if (descriptor_->is_packed() &&
HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize;\n");
@@ -884,7 +890,7 @@ GenerateParsingDoneCode(io::Printer* printer) const {
void RepeatedImmutableEnumFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
" output.writeRawVarint32($tag$);\n"
@@ -915,7 +921,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
printer->Print(
"size += dataSize;\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (!get$capitalized_name$List().isEmpty()) {"
" size += $tag_size$;\n"
@@ -928,7 +934,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
// cache the data size for packed fields.
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"$name$MemoizedSerializedSize = dataSize;\n");
}
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
new file mode 100644
index 00000000..697a07a7
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -0,0 +1,967 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum_field_lite.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
+ map<string, string>* variables) {
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] =
+ name_resolver->GetImmutableClassName(descriptor->enum_type());
+ (*variables)["mutable_type"] =
+ name_resolver->GetMutableClassName(descriptor->enum_type());
+ (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+ (*variables)["default_number"] = SimpleItoa(
+ descriptor->default_value_enum()->number());
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+ // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+ // by the proto compiler
+ (*variables)["deprecation"] = descriptor->options().deprecated()
+ ? "@java.lang.Deprecated " : "";
+ (*variables)["on_changed"] =
+ HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["clear_has_field_bit_message"] =
+ GenerateClearBit(messageBitIndex) + ";";
+
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["clear_has_field_bit_message"] = "";
+
+ (*variables)["is_field_present_message"] =
+ (*variables)["name"] + "_ != " +
+ (*variables)["default"] + ".getNumber()";
+ }
+
+ // For repeated builders, the underlying list tracks mutability state.
+ (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+ (*variables)["get_has_field_bit_from_local"] =
+ GenerateGetBitFromLocal(builderBitIndex);
+ (*variables)["set_has_field_bit_to_local"] =
+ GenerateSetBitToLocal(messageBitIndex);
+
+ if (SupportUnknownEnumValue(descriptor->file())) {
+ (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED";
+ } else {
+ (*variables)["unknown"] = (*variables)["default"];
+ }
+}
+
+} // namespace
+
+// ===================================================================
+
+ImmutableEnumFieldLiteGenerator::
+ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex),
+ name_resolver_(context->GetNameResolver()) {
+ SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 1;
+}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Value();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private int $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_message$;\n"
+ "}\n");
+ }
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value() {\n"
+ " return $name$_;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " $type$ result = $type$.valueOf($name$_);\n"
+ " return result == null ? $unknown$ : result;\n"
+ "}\n");
+
+ // Generate private setters for the builder to proxy into.
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$Value(int value) {\n"
+ " $set_has_field_bit_message$"
+ " $name$_ = value;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " $set_has_field_bit_message$\n"
+ " $name$_ = value.getNumber();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $clear_has_field_bit_message$\n"
+ " $name$_ = $default_number$;\n"
+ "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value() {\n"
+ " return instance.get$capitalized_name$Value();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$Value(int value);\n"
+ " return this;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // noop for enums
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $default_number$;\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+ } else if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "if (other.$name$_ != $default_number$) {\n"
+ " set$capitalized_name$Value(other.get$capitalized_name$Value());\n"
+ "}\n");
+ } else {
+ GOOGLE_LOG(FATAL) << "Can't reach here.";
+ }
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ // noop for scalars
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$set_has_field_bit_message$\n"
+ "$name$_ = rawValue;\n");
+ } else {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$type$ value = $type$.valueOf(rawValue);\n"
+ "if (value == null) {\n");
+ if (PreserveUnknownFields(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ " unknownFields.mergeVarintField($number$, rawValue);\n");
+ }
+ printer->Print(variables_,
+ "} else {\n"
+ " $set_has_field_bit_message$\n"
+ " $name$_ = rawValue;\n"
+ "}\n");
+ }
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for enums
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " output.writeEnum($number$, $name$_);\n"
+ "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeEnumSize($number$, $name$_);\n"
+ "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && $name$_ == other.$name$_;\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "hash = (37 * hash) + $constant_name$;\n"
+ "hash = (53 * hash) + $name$_;\n");
+}
+
+string ImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+// ===================================================================
+
+ImmutableEnumOneofFieldLiteGenerator::
+ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableEnumFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableEnumOneofFieldLiteGenerator::
+~ImmutableEnumOneofFieldLiteGenerator() {}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return (java.lang.Integer) $oneof_name$_;\n"
+ " }\n"
+ " return $default_number$;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+ " return result == null ? $unknown$ : result;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n");
+
+ // Generate private setters for the builder to proxy into.
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$Value(int value) {\n"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value.getNumber();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value() {\n"
+ " return instance.get$capitalized_name$Value();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$Value(value);\n"
+ " return this;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "set$capitalized_name$Value(other.get$capitalized_name$Value());\n");
+ } else {
+ printer->Print(variables_,
+ "set$capitalized_name$(other.get$capitalized_name$());\n");
+ }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = rawValue;\n");
+ } else {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$type$ value = $type$.valueOf(rawValue);\n"
+ "if (value == null) {\n");
+ if (PreserveUnknownFields(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ " unknownFields.mergeVarintField($number$, rawValue);\n");
+ }
+ printer->Print(variables_,
+ "} else {\n"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = rawValue;\n"
+ "}\n");
+ }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$Value()\n"
+ " == other.get$capitalized_name$Value();\n");
+ } else {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$()\n"
+ " .equals(other.get$capitalized_name$());\n");
+ }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "hash = (37 * hash) + $constant_name$;\n"
+ "hash = (53 * hash) + get$capitalized_name$Value();\n");
+ } else {
+ printer->Print(variables_,
+ "hash = (37 * hash) + $constant_name$;\n"
+ "hash = (53 * hash) + get$capitalized_name$().getNumber();\n");
+ }
+}
+
+// ===================================================================
+
+RepeatedImmutableEnumFieldLiteGenerator::
+RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+RepeatedImmutableEnumFieldLiteGenerator::
+~RepeatedImmutableEnumFieldLiteGenerator() {}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 0;
+}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+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$$type$ get$capitalized_name$(int index);\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<java.lang.Integer>\n"
+ "get$capitalized_name$ValueList();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Value(int index);\n");
+ }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ // TODO(dweis): Switch to IntList?
+ "private com.google.protobuf.Internal.ProtobufList<\n"
+ " java.lang.Integer> $name$_;\n"
+ "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
+ " java.lang.Integer, $type$> $name$_converter_ =\n"
+ " new com.google.protobuf.Internal.ListAdapter.Converter<\n"
+ " java.lang.Integer, $type$>() {\n"
+ " public $type$ convert(java.lang.Integer from) {\n"
+ " $type$ result = $type$.valueOf(from);\n"
+ " return result == null ? $unknown$ : result;\n"
+ " }\n"
+ " };\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return new com.google.protobuf.Internal.ListAdapter<\n"
+ " java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return $name$_.size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return $name$_converter_.convert($name$_.get(index));\n"
+ "}\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<java.lang.Integer>\n"
+ "get$capitalized_name$ValueList() {\n"
+ " return $name$_;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+ " return $name$_.get(index);\n"
+ "}\n");
+ }
+
+ if (descriptor_->options().packed() &&
+ HasGeneratedMethods(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ "private int $name$MemoizedSerializedSize;\n");
+ }
+
+ // Generate private setters for the builder to proxy into.
+ printer->Print(variables_,
+ "private void ensure$capitalized_name$IsMutable() {\n"
+ " if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList($name$_);\n"
+ " }\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, value.getNumber());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(value.getNumber());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " for ($type$ value : values) {\n"
+ " $name$_.add(value.getNumber());\n"
+ " }\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $name$_ = emptyProtobufList();\n"
+ "}\n");
+
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$Value(\n"
+ " int index, int value) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, value);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$Value(int value) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(value);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void addAll$capitalized_name$Value(\n"
+ " java.lang.Iterable<java.lang.Integer> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " for (int value : values) {\n"
+ " $name$_.add(value);\n"
+ " }\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return instance.get$capitalized_name$List();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return instance.get$capitalized_name$Count();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return instance.get$capitalized_name$(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " copyOnWrite();\n"
+ " instance.addAll$capitalized_name$(values);"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<java.lang.Integer>\n"
+ "get$capitalized_name$ValueList() {\n"
+ " return java.util.Collections.unmodifiableList(\n"
+ " instance.get$capitalized_name$ValueList());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+ " return instance.get$capitalized_name$Value(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Value(\n"
+ " int index, int value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$Value(index, value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$Value(int value) {\n"
+ " instance.add$capitalized_name$Value(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$Value(\n"
+ " java.lang.Iterable<java.lang.Integer> values) {\n"
+ " copyOnWrite();\n"
+ " instance.addAll$capitalized_name$Value(values);\n"
+ " return this;\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // noop for enums
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // The code below does two optimizations:
+ // 1. If the other list is empty, there's nothing to do. This ensures we
+ // don't allocate a new array if we already have an immutable one.
+ // 2. If the other list is non-empty and our current list is empty, we can
+ // reuse the other list which is guaranteed to be immutable.
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if ($name$_.isEmpty()) {\n"
+ " $name$_ = other.$name$_;\n"
+ " } else {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.addAll(other.$name$_);\n"
+ " }\n"
+ " $on_changed$\n"
+ "}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ // Read and store the enum
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList();\n"
+ "}\n"
+ "$name$_.add(rawValue);\n");
+ } else {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$type$ value = $type$.valueOf(rawValue);\n"
+ "if (value == null) {\n");
+ if (PreserveUnknownFields(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ " unknownFields.mergeVarintField($number$, rawValue);\n");
+ }
+ printer->Print(variables_,
+ "} else {\n"
+ " if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList();\n"
+ " }\n"
+ " $name$_.add(rawValue);\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+ // Wrap GenerateParsingCode's contents with a while loop.
+
+ printer->Print(variables_,
+ "int length = input.readRawVarint32();\n"
+ "int oldLimit = input.pushLimit(length);\n"
+ "while(input.getBytesUntilLimit() > 0) {\n");
+ printer->Indent();
+
+ GenerateParsingCode(printer);
+
+ printer->Outdent();
+ printer->Print(variables_,
+ "}\n"
+ "input.popLimit(oldLimit);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_mutable$) {\n"
+ " $name$_.makeImmutable();\n"
+ "}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (get$capitalized_name$List().size() > 0) {\n"
+ " output.writeRawVarint32($tag$);\n"
+ " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ "}\n"
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.writeEnumNoTag($name$_.get(i));\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.writeEnum($number$, $name$_.get(i));\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " int dataSize = 0;\n");
+ printer->Indent();
+
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " dataSize += com.google.protobuf.CodedOutputStream\n"
+ " .computeEnumSizeNoTag($name$_.get(i));\n"
+ "}\n");
+ printer->Print(
+ "size += dataSize;\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (!get$capitalized_name$List().isEmpty()) {"
+ " size += $tag_size$;\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeRawVarint32Size(dataSize);\n"
+ "}");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * $name$_.size();\n");
+ }
+
+ // cache the data size for packed fields.
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "$name$MemoizedSerializedSize = dataSize;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && $name$_.equals(other.$name$_);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (get$capitalized_name$Count() > 0) {\n"
+ " hash = (37 * hash) + $constant_name$;\n"
+ " hash = (53 * hash) + $name$_.hashCode();\n"
+ "}\n");
+}
+
+string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h
new file mode 100644
index 00000000..2c41c3e4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h
@@ -0,0 +1,159 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+ explicit ImmutableEnumFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableEnumFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(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;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ protected:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldLiteGenerator);
+};
+
+class ImmutableEnumOneofFieldLiteGenerator
+ : public ImmutableEnumFieldLiteGenerator {
+ public:
+ ImmutableEnumOneofFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableEnumOneofFieldLiteGenerator();
+
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableEnumFieldLiteGenerator
+ : public ImmutableFieldLiteGenerator {
+ public:
+ explicit RepeatedImmutableEnumFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableEnumFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 27cf416b..4db7085e 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -181,8 +181,9 @@ void ImmutableExtensionGenerator::Generate(io::Printer* printer) {
}
}
-void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
+int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
io::Printer* printer) {
+ int bytecode_estimate = 0;
if (descriptor_->extension_scope() == NULL &&
HasDescriptorMethods(descriptor_->file())) {
// Only applies to non-nested, non-lite extensions.
@@ -190,15 +191,18 @@ void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
"$name$.internalInit(descriptor.getExtensions().get($index$));\n",
"name", UnderscoresToCamelCase(descriptor_),
"index", SimpleItoa(descriptor_->index()));
+ bytecode_estimate += 21;
}
+ return bytecode_estimate;
}
-void ImmutableExtensionGenerator::GenerateRegistrationCode(
+int ImmutableExtensionGenerator::GenerateRegistrationCode(
io::Printer* printer) {
printer->Print(
"registry.add($scope$.$name$);\n",
"scope", scope_,
"name", UnderscoresToCamelCase(descriptor_));
+ return 7;
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h
index f1701fb5..bdd42263 100644
--- a/src/google/protobuf/compiler/java/java_extension.h
+++ b/src/google/protobuf/compiler/java/java_extension.h
@@ -67,8 +67,12 @@ class ExtensionGenerator {
virtual ~ExtensionGenerator() {}
virtual void Generate(io::Printer* printer) = 0;
- virtual void GenerateNonNestedInitializationCode(io::Printer* printer) = 0;
- virtual void GenerateRegistrationCode(io::Printer* printer) = 0;
+
+ // Returns an estimate of the number of bytes the printed code will compile to
+ virtual int GenerateNonNestedInitializationCode(io::Printer* printer) = 0;
+
+ // Returns an estimate of the number of bytes the printed code will compile to
+ virtual int GenerateRegistrationCode(io::Printer* printer) = 0;
protected:
static void InitTemplateVars(const FieldDescriptor* descriptor,
@@ -88,8 +92,8 @@ class ImmutableExtensionGenerator : public ExtensionGenerator {
virtual ~ImmutableExtensionGenerator();
virtual void Generate(io::Printer* printer);
- virtual void GenerateNonNestedInitializationCode(io::Printer* printer);
- virtual void GenerateRegistrationCode(io::Printer* printer);
+ virtual int GenerateNonNestedInitializationCode(io::Printer* printer);
+ virtual int GenerateRegistrationCode(io::Printer* printer);
protected:
const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index af9978e2..3f0fa11f 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -42,12 +42,18 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_enum_field_lite.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_lazy_message_field.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
#include <google/protobuf/compiler/java/java_map_field.h>
+#include <google/protobuf/compiler/java/java_map_field_lite.h>
#include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
#include <google/protobuf/compiler/java/java_primitive_field.h>
+#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
#include <google/protobuf/compiler/java/java_string_field.h>
+#include <google/protobuf/compiler/java/java_string_field_lite.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -133,6 +139,79 @@ ImmutableFieldGenerator* MakeImmutableGenerator(
}
}
+ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
+ const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
+ Context* context) {
+ if (field->is_repeated()) {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ if (IsMapEntry(field->message_type())) {
+ return new ImmutableMapFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ if (IsLazy(field)) {
+ return new RepeatedImmutableLazyMessageFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ return new RepeatedImmutableMessageFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ }
+ case JAVATYPE_ENUM:
+ return new RepeatedImmutableEnumFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ case JAVATYPE_STRING:
+ return new RepeatedImmutableStringFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ default:
+ return new RepeatedImmutablePrimitiveFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ } else {
+ if (field->containing_oneof()) {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ if (IsLazy(field)) {
+ return new ImmutableLazyMessageOneofFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ return new ImmutableMessageOneofFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ case JAVATYPE_ENUM:
+ return new ImmutableEnumOneofFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ case JAVATYPE_STRING:
+ return new ImmutableStringOneofFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ default:
+ return new ImmutablePrimitiveOneofFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ } else {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ if (IsLazy(field)) {
+ return new ImmutableLazyMessageFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ return new ImmutableMessageFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ case JAVATYPE_ENUM:
+ return new ImmutableEnumFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ case JAVATYPE_STRING:
+ return new ImmutableStringFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ default:
+ return new ImmutablePrimitiveFieldLiteGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ }
+ }
+}
+
static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
// Reaching here indicates a bug. Cases are:
@@ -153,6 +232,13 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const {
ReportUnexpectedPackedFieldsCall(printer);
}
+ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {}
+
+void ImmutableFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+ ReportUnexpectedPackedFieldsCall(printer);
+}
+
// ===================================================================
template <>
@@ -178,6 +264,28 @@ FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap(
template<>
FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {}
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap(
+ const Descriptor* descriptor, Context* context)
+ : descriptor_(descriptor),
+ field_generators_(new google::protobuf::scoped_ptr<
+ ImmutableFieldLiteGenerator>[descriptor->field_count()]) {
+ // Construct all the FieldGenerators and assign them bit indices for their
+ // bit fields.
+ int messageBitIndex = 0;
+ int builderBitIndex = 0;
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator(
+ descriptor->field(i), messageBitIndex, builderBitIndex, context);
+ field_generators_[i].reset(generator);
+ messageBitIndex += generator->GetNumBitsForMessage();
+ builderBitIndex += generator->GetNumBitsForBuilder();
+ }
+}
+
+template<>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap() {}
+
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
const FieldGeneratorInfo* info,
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index e8d6f3a2..00f3c601 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -93,6 +93,37 @@ class ImmutableFieldGenerator {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator);
};
+class ImmutableFieldLiteGenerator {
+ public:
+ ImmutableFieldLiteGenerator() {}
+ virtual ~ImmutableFieldLiteGenerator();
+
+ virtual int GetNumBitsForMessage() const = 0;
+ virtual int GetNumBitsForBuilder() const = 0;
+ virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0;
+ virtual void GenerateMembers(io::Printer* printer) const = 0;
+ virtual void GenerateBuilderMembers(io::Printer* printer) const = 0;
+ virtual void GenerateInitializationCode(io::Printer* printer) const = 0;
+ virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+ virtual void GenerateDynamicMethodMakeImmutableCode(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)
+ const = 0;
+
+ virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+ virtual void GenerateHashCode(io::Printer* printer) const = 0;
+
+ virtual string GetBoxedType() const = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldLiteGenerator);
+};
+
// Convenience class which constructs FieldGenerators for a Descriptor.
template<typename FieldGeneratorType>
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index f1e3cf67..68b47ee1 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -38,6 +38,7 @@
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
+#include <set>
#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum.h>
@@ -62,6 +63,19 @@ namespace java {
namespace {
+struct FieldDescriptorCompare {
+ bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) {
+ if(f1 == NULL) {
+ return false;
+ }
+ if(f2 == NULL) {
+ return true;
+ }
+ return f1->full_name() < f2->full_name();
+ }
+};
+
+typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> FieldDescriptorSet;
// Recursively searches the given message to collect extensions.
// Returns true if all the extensions can be recognized. The extensions will be
@@ -69,7 +83,7 @@ namespace {
// 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) {
+ FieldDescriptorSet* extensions) {
const Reflection* reflection = message.GetReflection();
// There are unknown fields that could be extensions, thus this call fails.
@@ -79,7 +93,7 @@ bool CollectExtensions(const Message& message,
reflection->ListFields(message, &fields);
for (int i = 0; i < fields.size(); i++) {
- if (fields[i]->is_extension()) extensions->push_back(fields[i]);
+ if (fields[i]->is_extension()) extensions->insert(fields[i]);
if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
if (fields[i]->is_repeated()) {
@@ -106,7 +120,7 @@ bool CollectExtensions(const Message& message,
// in order to handle this case.
void CollectExtensions(const FileDescriptorProto& file_proto,
const DescriptorPool& alternate_pool,
- vector<const FieldDescriptor*>* extensions,
+ FieldDescriptorSet* extensions,
const string& file_data) {
if (!CollectExtensions(file_proto, extensions)) {
// There are unknown fields in the file_proto, which are probably
@@ -139,6 +153,42 @@ void CollectExtensions(const FileDescriptorProto& file_proto,
}
}
+// Compare two field descriptors, returning true if the first should come
+// before the second.
+bool CompareFieldsByName(const FieldDescriptor *a, const FieldDescriptor *b) {
+ return a->full_name() < b->full_name();
+}
+
+// Our static initialization methods can become very, very large.
+// So large that if we aren't careful we end up blowing the JVM's
+// 64K bytes of bytecode/method. Fortunately, since these static
+// methods are executed only once near the beginning of a program,
+// there's usually plenty of stack space available and we can
+// extend our methods by simply chaining them to another method
+// with a tail call. This inserts the sequence call-next-method,
+// end this one, begin-next-method as needed.
+void MaybeRestartJavaMethod(io::Printer* printer,
+ int *bytecode_estimate,
+ int *method_num,
+ const char *chain_statement,
+ const char *method_decl) {
+ // The goal here is to stay under 64K bytes of jvm bytecode/method,
+ // since otherwise we hit a hardcoded limit in the jvm and javac will
+ // then fail with the error "code too large". This limit lets our
+ // estimates be off by a factor of two and still we're okay.
+ static const int bytesPerMethod = 1<<15; // aka 32K
+
+ if ((*bytecode_estimate) > bytesPerMethod) {
+ ++(*method_num);
+ printer->Print(chain_statement, "method_num", SimpleItoa(*method_num));
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(method_decl, "method_num", SimpleItoa(*method_num));
+ printer->Indent();
+ *bytecode_estimate = 0;
+ }
+}
+
} // namespace
@@ -270,9 +320,16 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Print(
"static {\n");
printer->Indent();
+ int bytecode_estimate = 0;
+ int method_num = 0;
for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateStaticVariableInitializers(printer);
+ bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
+ MaybeRestartJavaMethod(
+ printer,
+ &bytecode_estimate, &method_num,
+ "_clinit_autosplit_$method_num$();\n",
+ "private static void _clinit_autosplit_$method_num$() {\n");
}
printer->Outdent();
@@ -303,12 +360,24 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
SharedCodeGenerator shared_code_generator(file_);
shared_code_generator.GenerateDescriptors(printer);
+ int bytecode_estimate = 0;
+ int method_num = 0;
for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateStaticVariableInitializers(printer);
+ bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
+ MaybeRestartJavaMethod(
+ printer,
+ &bytecode_estimate, &method_num,
+ "_clinit_autosplit_dinit_$method_num$();\n",
+ "private static void _clinit_autosplit_dinit_$method_num$() {\n");
}
for (int i = 0; i < file_->extension_count(); i++) {
- extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
+ bytecode_estimate += extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
+ MaybeRestartJavaMethod(
+ printer,
+ &bytecode_estimate, &method_num,
+ "_clinit_autosplit_dinit_$method_num$();\n",
+ "private static void _clinit_autosplit_dinit_$method_num$() {\n");
}
// Proto compiler builds a DescriptorPool, which holds all the descriptors to
@@ -330,7 +399,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
file_->CopyTo(&file_proto);
string file_data;
file_proto.SerializeToString(&file_data);
- vector<const FieldDescriptor*> extensions;
+ FieldDescriptorSet extensions;
CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
if (extensions.size() > 0) {
@@ -339,10 +408,17 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
printer->Print(
"com.google.protobuf.ExtensionRegistry registry =\n"
" com.google.protobuf.ExtensionRegistry.newInstance();\n");
- for (int i = 0; i < extensions.size(); i++) {
+ FieldDescriptorSet::iterator it;
+ for (it = extensions.begin(); it != extensions.end(); it++) {
google::protobuf::scoped_ptr<ExtensionGenerator> generator(
- generator_factory_->NewExtensionGenerator(extensions[i]));
- generator->GenerateRegistrationCode(printer);
+ generator_factory_->NewExtensionGenerator(*it));
+ bytecode_estimate += generator->GenerateRegistrationCode(printer);
+ MaybeRestartJavaMethod(
+ printer,
+ &bytecode_estimate, &method_num,
+ "_clinit_autosplit_dinit_$method_num$(registry);\n",
+ "private static void _clinit_autosplit_dinit_$method_num$(\n"
+ " com.google.protobuf.ExtensionRegistry registry) {\n");
}
printer->Print(
"com.google.protobuf.Descriptors.FileDescriptor\n"
@@ -394,7 +470,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer*
file_->CopyTo(&file_proto);
string file_data;
file_proto.SerializeToString(&file_data);
- vector<const FieldDescriptor*> extensions;
+ FieldDescriptorSet extensions;
CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
if (extensions.size() > 0) {
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
index 2d1437f0..92ef851b 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.cc
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/compiler/java/java_field.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_message.h>
+#include <google/protobuf/compiler/java/java_message_lite.h>
#include <google/protobuf/compiler/java/java_service.h>
namespace google {
@@ -57,7 +58,12 @@ ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {}
MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
const Descriptor* descriptor) const {
- return new ImmutableMessageGenerator(descriptor, context_);
+ if (descriptor->file()->options().optimize_for() ==
+ FileOptions::LITE_RUNTIME) {
+ return new ImmutableMessageLiteGenerator(descriptor, context_);
+ } else {
+ return new ImmutableMessageGenerator(descriptor, context_);
+ }
}
ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 23685385..e24894b1 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -690,8 +690,8 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); i++) {
fields[i] = descriptor->field(i);
}
- sort(fields, fields + descriptor->field_count(),
- FieldOrderingByNumber());
+ std::sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
return fields;
}
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index d957fdc4..96d2545f 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -196,12 +196,6 @@ inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
FileOptions::LITE_RUNTIME;
}
-inline bool HasNestedBuilders(const Descriptor* descriptor) {
- // The proto-lite version doesn't support nested builders.
- return descriptor->file()->options().optimize_for() !=
- FileOptions::LITE_RUNTIME;
-}
-
// Should we generate generic services for this file?
inline bool HasGenericServices(const FileDescriptor *file) {
return file->service_count() > 0 &&
@@ -297,6 +291,16 @@ struct ExtensionRangeOrdering {
// and return it. The caller should delete the returned array.
const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor);
+// Does this message class have any packed fields?
+inline bool HasPackedFields(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ if (descriptor->field(i)->is_packed()) {
+ return true;
+ }
+ }
+ return false;
+}
+
// Check a message type and its sub-message types recursively to see if any of
// them has a required field. Return true if a required field is found.
bool HasRequiredFields(const Descriptor* descriptor);
@@ -320,6 +324,10 @@ inline bool IsMapEntry(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}
+inline bool IsMapField(const FieldDescriptor* descriptor) {
+ return descriptor->is_map();
+}
+
inline bool PreserveUnknownFields(const Descriptor* descriptor) {
return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
}
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
index 21cab7db..0de8cbe5 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
@@ -72,14 +72,12 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return ($type$) $name$_.getValue($type$.getDefaultInstance());\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"
- "}\n");
- }
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " return $name$_;\n"
+ "}\n");
}
void ImmutableLazyMessageFieldGenerator::
@@ -92,14 +90,12 @@ GenerateBuilderMembers(io::Printer* printer) const {
"private com.google.protobuf.LazyFieldLite $name$_ =\n"
" new com.google.protobuf.LazyFieldLite();\n");
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_,
- // If this builder is non-null, it is used and the other fields are
- // ignored.
- "private com.google.protobuf.SingleFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
- "\n");
- }
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+ "\n");
// The comments above the methods below are based on a hypothetical
// field of type "Field" called "Field".
@@ -179,39 +175,37 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$clear_has_field_bit_builder$;\n"
"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");
- 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");
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "private com.google.protobuf.SingleFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> \n"
- " get$capitalized_name$FieldBuilder() {\n"
- " if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder>(\n"
- " $name$_,\n"
- " getParentForChildren(),\n"
- " isClean());\n"
- " $name$_ = null;\n"
- " }\n"
- " return $name$Builder_;\n"
- "}\n");
- }
+ 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");
+ 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");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> \n"
+ " get$capitalized_name$FieldBuilder() {\n"
+ " if ($name$Builder_ == null) {\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " $name$_,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $name$_ = null;\n"
+ " }\n"
+ " return $name$Builder_;\n"
+ "}\n");
}
@@ -243,9 +237,8 @@ GenerateBuildingCode(io::Printer* printer) const {
"}\n");
printer->Print(variables_,
- "result.$name$_.setByteString(\n"
- " $name$_.toByteString(),\n"
- " $name$_.getExtensionRegistry());\n");
+ "result.$name$_.set(\n"
+ " $name$_);\n");
}
void ImmutableLazyMessageFieldGenerator::
@@ -425,9 +418,8 @@ GenerateBuildingCode(io::Printer* printer) const {
printer->Print(variables_,
"result.$oneof_name$_ = new $lazy_type$();\n"
- "(($lazy_type$) result.$oneof_name$_).setByteString(\n"
- " (($lazy_type$) $oneof_name$_).toByteString(),\n"
- " (($lazy_type$) $oneof_name$_).getExtensionRegistry());\n");
+ "(($lazy_type$) result.$oneof_name$_).set(\n"
+ " (($lazy_type$) $oneof_name$_));\n");
printer->Outdent();
printer->Print("}\n");
}
@@ -540,14 +532,12 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n"
"\n");
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_,
- // If this builder is non-null, it is used and the other fields are
- // ignored.
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
- "\n");
- }
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+ "\n");
// The comments above the methods below are based on a hypothetical
// repeated field of type "Field" called "RepeatedField".
@@ -725,70 +715,68 @@ 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");
+ 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");
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
- " int index) {\n"
- " if ($name$Builder_ == null) {\n"
- " return $name$_.get(index);"
- " } else {\n"
- " return $name$Builder_.getMessageOrBuilder(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"
+ " return $name$_.get(index);"
+ " } else {\n"
+ " return $name$Builder_.getMessageOrBuilder(index);\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"
- " return $name$Builder_.getMessageOrBuilderList();\n"
- " } else {\n"
- " return java.util.Collections.unmodifiableList($name$_);\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"
+ " return $name$Builder_.getMessageOrBuilderList();\n"
+ " } else {\n"
+ " return java.util.Collections.unmodifiableList($name$_);\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");
- 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");
- 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"
- "}\n"
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> \n"
- " get$capitalized_name$FieldBuilder() {\n"
- " if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder>(\n"
- " $name$_,\n"
- " $get_mutable_bit_builder$,\n"
- " getParentForChildren(),\n"
- " isClean());\n"
- " $name$_ = null;\n"
- " }\n"
- " return $name$Builder_;\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");
+ 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");
+ 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"
+ "}\n"
+ "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> \n"
+ " get$capitalized_name$FieldBuilder() {\n"
+ " if ($name$Builder_ == null) {\n"
+ " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " $name$_,\n"
+ " $get_mutable_bit_builder$,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $name$_ = null;\n"
+ " }\n"
+ " return $name$Builder_;\n"
+ "}\n");
}
void RepeatedImmutableLazyMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
new file mode 100644
index 00000000..283ba1d3
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -0,0 +1,708 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableLazyMessageFieldLiteGenerator::
+ImmutableLazyMessageFieldLiteGenerator(
+ const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableMessageFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+ImmutableLazyMessageFieldLiteGenerator::
+~ImmutableLazyMessageFieldLiteGenerator() {}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private com.google.protobuf.LazyFieldLite $name$_ =\n"
+ " new com.google.protobuf.LazyFieldLite();\n");
+
+ PrintExtraFieldInfo(variables_, printer);
+ 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 ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " $name$_.setValue(value);\n"
+ " $set_has_field_bit_message$;\n"
+ "}\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " $name$_.setValue(builderForValue.build());\n"
+ " $set_has_field_bit_message$;\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void merge$capitalized_name$($type$ value) {\n"
+ " if ($get_has_field_bit_message$ &&\n"
+ " !$name$_.containsDefaultInstance()) {\n"
+ " $name$_.setValue(\n"
+ " $type$.newBuilder(\n"
+ " get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+ " } else {\n"
+ " $name$_.setValue(value);\n"
+ " }\n"
+ " $set_has_field_bit_message$;\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $name$_.clear();\n"
+ " $clear_has_field_bit_message$;\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // The comments above the methods below are based on a hypothetical
+ // field of type "Field" called "Field".
+
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.merge$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.clear();\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " $name$_.merge(other.$name$_);\n"
+ " $set_has_field_bit_message$;\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.setByteString(input.readBytes(), extensionRegistry);\n");
+ printer->Print(variables_,
+ "$set_has_field_bit_message$;\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ // Do not de-serialize lazy fields.
+ printer->Print(variables_,
+ "if ($get_has_field_bit_message$) {\n"
+ " output.writeBytes($number$, $name$_.toByteString());\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeLazyFieldSize($number$, $name$_);\n"
+ "}\n");
+}
+
+// ===================================================================
+
+ImmutableLazyMessageOneofFieldLiteGenerator::
+ImmutableLazyMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableLazyMessageFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+ variables_["lazy_type"] = "com.google.protobuf.LazyFieldLite";
+}
+
+ImmutableLazyMessageOneofFieldLiteGenerator::
+~ImmutableLazyMessageOneofFieldLiteGenerator() {}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n"
+ " $type$.getDefaultInstance());\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ " $set_oneof_case_message$;\n"
+ " }\n"
+ " (($lazy_type$) $oneof_name$_).setValue(value);\n"
+ "}\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ " $set_oneof_case_message$;\n"
+ " }\n"
+ " (($lazy_type$) $oneof_name$_).setValue(builderForValue.build());\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void merge$capitalized_name$($type$ value) {\n"
+ " if ($has_oneof_case_message$ &&\n"
+ " !(($lazy_type$) $oneof_name$_).containsDefaultInstance()) {\n"
+ " (($lazy_type$) $oneof_name$_).setValue(\n"
+ " $type$.newBuilder(\n"
+ " get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+ " } else {\n"
+ " if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ " $set_oneof_case_message$;\n"
+ " }\n"
+ " (($lazy_type$) $oneof_name$_).setValue(value);\n"
+ " }\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.merge$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ "}\n"
+ "(($lazy_type$) $oneof_name$_).merge(\n"
+ " ($lazy_type$) other.$oneof_name$_);\n"
+ "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ "}\n"
+ "(($lazy_type$) $oneof_name$_).setByteString(\n"
+ " input.readBytes(), extensionRegistry);\n"
+ "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ // Do not de-serialize lazy fields.
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.writeBytes(\n"
+ " $number$, (($lazy_type$) $oneof_name$_).toByteString());\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeLazyFieldSize($number$, ($lazy_type$) $oneof_name$_);\n"
+ "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableLazyMessageFieldLiteGenerator::
+RepeatedImmutableLazyMessageFieldLiteGenerator(
+ const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : RepeatedImmutableMessageFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+
+RepeatedImmutableLazyMessageFieldLiteGenerator::
+~RepeatedImmutableLazyMessageFieldLiteGenerator() {}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private com.google.protobuf.Internal.ProtobufList<\n"
+ " com.google.protobuf.LazyFieldLite> $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$>\n"
+ " get$capitalized_name$List() {\n"
+ " java.util.List<$type$> list =\n"
+ " new java.util.ArrayList<$type$>($name$_.size());\n"
+ " for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n"
+ " list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n"
+ " }\n"
+ // TODO(dweis): Make this list immutable?
+ " return list;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<? extends $type$OrBuilder>\n"
+ " get$capitalized_name$OrBuilderList() {\n"
+ " return get$capitalized_name$List();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return $name$_.size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return ($type$)\n"
+ " $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+ " int index) {\n"
+ " return ($type$OrBuilder)\n"
+ " $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+ "}\n");
+
+ printer->Print(variables_,
+ "private void ensure$capitalized_name$IsMutable() {\n"
+ " if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList($name$_);\n"
+ " }\n"
+ "}\n"
+ "\n");
+
+ // Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(\n"
+ " index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+ "}\n");
+
+ // Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+ " builderForValue.build()));\n"
+ "}\n");
+
+ // Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(\n"
+ " index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+ "}\n");
+
+ // Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(\n"
+ " builderForValue.build()));\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+ " builderForValue.build()));\n"
+ "}\n");
+
+ // Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " for (com.google.protobuf.MessageLite v : values) {\n"
+ " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(v));\n"
+ " }\n"
+ "}\n");
+
+ // Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $name$_ = emptyProtobufList();\n"
+ "}\n");
+
+ // Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void remove$capitalized_name$(int index) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.remove(index);\n"
+ "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // List<Field> getRepeatedFieldList()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return java.util.Collections.unmodifiableList(\n"
+ " instance.get$capitalized_name$List());\n"
+ "}\n");
+
+ // int getRepeatedFieldCount()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return instance.get$capitalized_name$Count();\n"
+ "}\n");
+
+ // Field getRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return instance.get$capitalized_name$(index);\n"
+ "}\n");
+
+ // Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(index, builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " copyOnWrite();\n"
+ " instance.addAll$capitalized_name$(values);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder remove$capitalized_name$(int index) {\n"
+ " copyOnWrite();\n"
+ " instance.remove$capitalized_name$(index);\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList();\n"
+ "}\n"
+ "$name$_.add(new com.google.protobuf.LazyFieldLite(\n"
+ " extensionRegistry, input.readBytes()));\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.writeBytes($number$, $name$_.get(i).toByteString());\n"
+ "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeLazyFieldSize($number$, $name$_.get(i));\n"
+ "}\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h
new file mode 100644
index 00000000..e85ec0f3
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableLazyMessageFieldLiteGenerator
+ : public ImmutableMessageFieldLiteGenerator {
+ public:
+ explicit ImmutableLazyMessageFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableLazyMessageFieldLiteGenerator();
+
+ // overroads ImmutableMessageFieldLiteGenerator ------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageFieldLiteGenerator);
+};
+
+class ImmutableLazyMessageOneofFieldLiteGenerator
+ : public ImmutableLazyMessageFieldLiteGenerator {
+ public:
+ ImmutableLazyMessageOneofFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableLazyMessageOneofFieldLiteGenerator();
+
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableLazyMessageFieldLiteGenerator
+ : public RepeatedImmutableMessageFieldLiteGenerator {
+ public:
+ explicit RepeatedImmutableLazyMessageFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableLazyMessageFieldLiteGenerator();
+
+ // overroads RepeatedImmutableMessageFieldLiteGenerator ----------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableLazyMessageFieldLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 2986f51f..44b86cd7 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -133,9 +133,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["set_mutable_bit_parser"] =
GenerateSetBitMutableLocal(builderBitIndex);
+ (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+ "DefaultEntryHolder.defaultEntry";
if (HasDescriptorMethods(descriptor->file())) {
(*variables)["lite"] = "";
- (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry";
+ (*variables)["map_field_parameter"] = (*variables)["default_entry"];
(*variables)["descriptor"] =
name_resolver->GetImmutableClassName(descriptor->file()) +
".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
@@ -154,9 +156,7 @@ ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
Context* context)
- : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex), context_(context),
- name_resolver_(context->GetNameResolver()) {
+ : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
context->GetFieldGeneratorInfo(descriptor),
name_resolver_, &variables_);
@@ -201,22 +201,29 @@ void ImmutableMapFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
- "private static final com.google.protobuf.MapEntry$lite$<\n"
- " $type_parameters$> $name$DefaultEntry =\n"
- " com.google.protobuf.MapEntry$lite$\n"
- " .<$type_parameters$>newDefaultInstance(\n"
- " $descriptor$\n"
- " $key_wire_type$,\n"
- " $key_default_value$,\n"
- " $value_wire_type$,\n"
- " $value_default_value$);\n");
+ "private static final class $capitalized_name$DefaultEntryHolder {\n"
+ " static final com.google.protobuf.MapEntry$lite$<\n"
+ " $type_parameters$> defaultEntry =\n"
+ " com.google.protobuf.MapEntry$lite$\n"
+ " .<$type_parameters$>newDefaultInstance(\n"
+ " $descriptor$\n"
+ " $key_wire_type$,\n"
+ " $key_default_value$,\n"
+ " $value_wire_type$,\n"
+ " $value_default_value$);\n"
+ "}\n");
printer->Print(
variables_,
"private com.google.protobuf.MapField$lite$<\n"
- " $type_parameters$> $name$_ =\n"
- " com.google.protobuf.MapField$lite$.emptyMapField(\n"
- " $map_field_parameter$);\n"
- "\n");
+ " $type_parameters$> $name$_;\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGet$capitalized_name$() {\n"
+ " if ($name$_ == null) {\n"
+ " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+ " $map_field_parameter$);\n"
+ " }\n"
+ " return $name$_;\n"
+ "}\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
printer->Print(
variables_,
@@ -233,7 +240,7 @@ GenerateMembers(io::Printer* printer) const {
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
"get$capitalized_name$Value() {\n"
- " return $name$_.getMap();\n"
+ " return internalGet$capitalized_name$().getMap();\n"
"}\n");
}
WriteFieldDocComment(printer, descriptor_);
@@ -244,7 +251,8 @@ GenerateMembers(io::Printer* printer) const {
"get$capitalized_name$() {\n"
" return new com.google.protobuf.Internal.MapAdapter<\n"
" $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " $name$_.getMap(), $name$ValueConverter);\n"
+ " internalGet$capitalized_name$().getMap(),\n"
+ " $name$ValueConverter);\n"
"}\n");
} else {
WriteFieldDocComment(printer, descriptor_);
@@ -252,7 +260,7 @@ GenerateMembers(io::Printer* printer) const {
variables_,
"$deprecation$\n"
"public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
- " return $name$_.getMap();\n"
+ " return internalGet$capitalized_name$().getMap();\n"
"}\n");
}
}
@@ -262,10 +270,27 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(
variables_,
"private com.google.protobuf.MapField$lite$<\n"
- " $type_parameters$> $name$_ =\n"
- " com.google.protobuf.MapField$lite$.newMapField(\n"
- " $map_field_parameter$);\n"
- "\n");
+ " $type_parameters$> $name$_;\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGet$capitalized_name$() {\n"
+ " if ($name$_ == null) {\n"
+ " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+ " $map_field_parameter$);\n"
+ " }\n"
+ " return $name$_;\n"
+ "}\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGetMutable$capitalized_name$() {\n"
+ " $on_changed$;\n"
+ " if ($name$_ == null) {\n"
+ " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+ " $map_field_parameter$);\n"
+ " }\n"
+ " if (!$name$_.isMutable()) {\n"
+ " $name$_ = $name$_.copy();\n"
+ " }\n"
+ " return $name$_;\n"
+ "}\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
WriteFieldDocComment(printer, descriptor_);
printer->Print(
@@ -275,7 +300,8 @@ GenerateBuilderMembers(io::Printer* printer) const {
"get$capitalized_name$() {\n"
" return new com.google.protobuf.Internal.MapAdapter<\n"
" $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " $name$_.getMap(), $name$ValueConverter);\n"
+ " internalGet$capitalized_name$().getMap(),\n"
+ " $name$ValueConverter);\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
@@ -283,10 +309,10 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
"getMutable$capitalized_name$() {\n"
- " $on_changed$\n"
" return new com.google.protobuf.Internal.MapAdapter<\n"
" $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " $name$_.getMutableMap(), $name$ValueConverter);\n"
+ " internalGetMutable$capitalized_name$().getMutableMap(),\n"
+ " $name$ValueConverter);\n"
"}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
WriteFieldDocComment(printer, descriptor_);
@@ -295,7 +321,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
"get$capitalized_name$Value() {\n"
- " return $name$_.getMap();\n"
+ " return internalGet$capitalized_name$().getMap();\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
@@ -303,8 +329,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
"getMutable$capitalized_name$Value() {\n"
- " $on_changed$\n"
- " return $name$_.getMutableMap();\n"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
}
} else {
@@ -312,15 +337,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(
variables_,
"public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
- " return $name$_.getMap();\n"
+ " return internalGet$capitalized_name$().getMap();\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"public java.util.Map<$type_parameters$>\n"
"getMutable$capitalized_name$() {\n"
- " $on_changed$\n"
- " return $name$_.getMutableMap();\n"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
}
}
@@ -339,24 +363,23 @@ void ImmutableMapFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(
variables_,
- "$name$_.clear();\n");
+ "internalGetMutable$capitalized_name$().clear();\n");
}
void ImmutableMapFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(
variables_,
- "$name$_.mergeFrom(other.$name$_);\n");
+ "internalGetMutable$capitalized_name$().mergeFrom(\n"
+ " other.internalGet$capitalized_name$());\n");
}
void ImmutableMapFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
printer->Print(
variables_,
- // We do a copy of the map field to ensure that the built result is
- // immutable. Implementation of this copy() method can do copy-on-write
- // to defer this copy until further modifications are made on the field.
- "result.$name$_ = $name$_.copy();\n");
+ "result.$name$_ = internalGet$capitalized_name$();\n"
+ "result.$name$_.makeImmutable();\n");
}
void ImmutableMapFieldGenerator::
@@ -374,7 +397,7 @@ GenerateParsingCode(io::Printer* printer) const {
variables_,
"com.google.protobuf.ByteString bytes = input.readBytes();\n"
"com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n");
+ "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
printer->Print(
variables_,
"if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
@@ -387,7 +410,7 @@ GenerateParsingCode(io::Printer* printer) const {
variables_,
"com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
"$name$ = input.readMessage(\n"
- " $name$DefaultEntry.getParserForType(), extensionRegistry);\n"
+ " $default_entry$.getParserForType(), extensionRegistry);\n"
"$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
}
}
@@ -402,9 +425,9 @@ GenerateSerializationCode(io::Printer* printer) const {
printer->Print(
variables_,
"for (java.util.Map.Entry<$type_parameters$> entry\n"
- " : $name$_.getMap().entrySet()) {\n"
+ " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
" com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- " $name$ = $name$DefaultEntry.newBuilderForType()\n"
+ " $name$ = $default_entry$.newBuilderForType()\n"
" .setKey(entry.getKey())\n"
" .setValue(entry.getValue())\n"
" .build();\n"
@@ -417,9 +440,9 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(
variables_,
"for (java.util.Map.Entry<$type_parameters$> entry\n"
- " : $name$_.getMap().entrySet()) {\n"
+ " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
" com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- " $name$ = $name$DefaultEntry.newBuilderForType()\n"
+ " $name$ = $default_entry$.newBuilderForType()\n"
" .setKey(entry.getKey())\n"
" .setValue(entry.getValue())\n"
" .build();\n"
@@ -432,16 +455,17 @@ void ImmutableMapFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(
variables_,
- "result = result && $name$_.equals(other.$name$_);\n");
+ "result = result && internalGet$capitalized_name$().equals(\n"
+ " other.internalGet$capitalized_name$());\n");
}
void ImmutableMapFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(
variables_,
- "if (!$name$_.getMap().isEmpty()) {\n"
+ "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
" hash = (37 * hash) + $constant_name$;\n"
- " hash = (53 * hash) + $name$_.hashCode();\n"
+ " hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index 80a94f45..f2768f3a 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -68,9 +68,6 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
private:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
- const int messageBitIndex_;
- const int builderBitIndex_;
- Context* context_;
ClassNameResolver* name_resolver_;
};
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
new file mode 100644
index 00000000..cd1698f0
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -0,0 +1,459 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_map_field_lite.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ GOOGLE_CHECK(message->options().map_entry());
+ return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ GOOGLE_CHECK(message->options().map_entry());
+ return message->FindFieldByName("value");
+}
+
+string TypeName(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver,
+ bool boxed) {
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ return name_resolver->GetImmutableClassName(field->message_type());
+ } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+ return name_resolver->GetImmutableClassName(field->enum_type());
+ } else {
+ return boxed ? BoxedPrimitiveTypeName(GetJavaType(field))
+ : PrimitiveTypeName(GetJavaType(field));
+ }
+}
+
+string WireType(const FieldDescriptor* field) {
+ return "com.google.protobuf.WireFormat.FieldType." +
+ string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
+ map<string, string>* variables) {
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] =
+ name_resolver->GetImmutableClassName(descriptor->message_type());
+ const FieldDescriptor* key = KeyField(descriptor);
+ const FieldDescriptor* value = ValueField(descriptor);
+ (*variables)["key_type"] = TypeName(key, name_resolver, false);
+ (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+ (*variables)["key_wire_type"] = WireType(key);
+ (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
+ // We store enums as Integers internally.
+ (*variables)["value_type"] = "int";
+ (*variables)["boxed_value_type"] = "java.lang.Integer";
+ (*variables)["value_wire_type"] = WireType(value);
+ (*variables)["value_default_value"] =
+ DefaultValue(value, true, name_resolver) + ".getNumber()";
+
+ (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
+
+ if (SupportUnknownEnumValue(descriptor->file())) {
+ // Map unknown values to a special UNRECOGNIZED value if supported.
+ (*variables)["unrecognized_value"] =
+ (*variables)["value_enum_type"] + ".UNRECOGNIZED";
+ } else {
+ // Map unknown values to the default value if we don't have UNRECOGNIZED.
+ (*variables)["unrecognized_value"] =
+ DefaultValue(value, true, name_resolver);
+ }
+ } else {
+ (*variables)["value_type"] = TypeName(value, name_resolver, false);
+ (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
+ (*variables)["value_wire_type"] = WireType(value);
+ (*variables)["value_default_value"] =
+ DefaultValue(value, true, name_resolver);
+ }
+ (*variables)["type_parameters"] =
+ (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+ // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+ // by the proto compiler
+ (*variables)["deprecation"] = descriptor->options().deprecated()
+ ? "@java.lang.Deprecated " : "";
+ (*variables)["on_changed"] =
+ HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+ (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+ "DefaultEntryHolder.defaultEntry";
+ (*variables)["lite"] = "Lite";
+ (*variables)["descriptor"] = "";
+}
+
+} // namespace
+
+ImmutableMapFieldLiteGenerator::
+ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+ SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+ImmutableMapFieldLiteGenerator::
+~ImmutableMapFieldLiteGenerator() {}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 0;
+}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$();\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$Value();\n");
+ }
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$();\n");
+ }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "private static final class $capitalized_name$DefaultEntryHolder {\n"
+ " static final com.google.protobuf.MapEntry$lite$<\n"
+ " $type_parameters$> defaultEntry =\n"
+ " com.google.protobuf.MapEntry$lite$\n"
+ " .<$type_parameters$>newDefaultInstance(\n"
+ " $descriptor$\n"
+ " $key_wire_type$,\n"
+ " $key_default_value$,\n"
+ " $value_wire_type$,\n"
+ " $value_default_value$);\n"
+ "}\n");
+ printer->Print(
+ variables_,
+ "private com.google.protobuf.MapField$lite$<\n"
+ " $type_parameters$> $name$_ =\n"
+ " com.google.protobuf.MapField$lite$.emptyMapField();\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGet$capitalized_name$() {\n"
+ " return $name$_;\n"
+ "}\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGetMutable$capitalized_name$() {\n"
+ " if (!$name$_.isMutable()) {\n"
+ " $name$_ = $name$_.copy();\n"
+ " }\n"
+ " return $name$_;\n"
+ "}\n");
+ if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ printer->Print(
+ variables_,
+ "private static final\n"
+ "com.google.protobuf.Internal.MapAdapter.Converter<\n"
+ " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
+ " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
+ " $value_enum_type$.internalGetValueMap(),\n"
+ " $unrecognized_value$);\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "get$capitalized_name$Value() {\n"
+ " return internalGet$capitalized_name$().getMap();\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$() {\n"
+ " return new com.google.protobuf.Internal.MapAdapter<\n"
+ " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+ " internalGet$capitalized_name$().getMap(),\n"
+ " $name$ValueConverter);\n"
+ "}\n");
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+ " return internalGet$capitalized_name$().getMap();\n"
+ "}\n");
+ }
+
+ // Generate private setters for the builder to proxy into.
+ if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "getMutable$capitalized_name$() {\n"
+ " return new com.google.protobuf.Internal.MapAdapter<\n"
+ " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+ " internalGetMutable$capitalized_name$().getMutableMap(),\n"
+ " $name$ValueConverter);\n"
+ "}\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "getMutable$capitalized_name$Value() {\n"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "}\n");
+ }
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "private java.util.Map<$type_parameters$>\n"
+ "getMutable$capitalized_name$() {\n"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "}\n");
+ }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "getMutable$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " return instance.getMutable$capitalized_name$();\n"
+ "}\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "get$capitalized_name$Value() {\n"
+ " return instance.get$capitalized_name$Value();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "getMutable$capitalized_name$Value() {\n"
+ " copyOnWrite();\n"
+ " return instance.getMutable$capitalized_name$Value();\n"
+ "}\n");
+ }
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "public java.util.Map<$type_parameters$>\n"
+ "getMutable$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " return instance.getMutable$capitalized_name$();\n"
+ "}\n");
+ }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // Nothing to initialize.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ // Nothing to initialize.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "internalGetMutable$capitalized_name$().mergeFrom(\n"
+ " other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.makeImmutable();\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "if (!$name$_.isMutable()) {\n"
+ " $name$_ = $name$_.copy();\n"
+ "}\n");
+ if (!SupportUnknownEnumValue(descriptor_->file()) &&
+ GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ printer->Print(
+ variables_,
+ "com.google.protobuf.ByteString bytes = input.readBytes();\n"
+ "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
+ printer->Print(
+ variables_,
+ "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
+ " unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
+ "} else {\n"
+ " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
+ "}\n");
+ } else {
+ printer->Print(
+ variables_,
+ "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ "$name$ = input.readMessage(\n"
+ " $default_entry$.getParserForType(), extensionRegistry);\n"
+ "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
+ }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // Nothing to do here.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "for (java.util.Map.Entry<$type_parameters$> entry\n"
+ " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+ " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ " $name$ = $default_entry$.newBuilderForType()\n"
+ " .setKey(entry.getKey())\n"
+ " .setValue(entry.getValue())\n"
+ " .build();\n"
+ " output.writeMessage($number$, $name$);\n"
+ "}\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "for (java.util.Map.Entry<$type_parameters$> entry\n"
+ " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+ " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ " $name$ = $default_entry$.newBuilderForType()\n"
+ " .setKey(entry.getKey())\n"
+ " .setValue(entry.getValue())\n"
+ " .build();\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeMessageSize($number$, $name$);\n"
+ "}\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "result = result && internalGet$capitalized_name$().equals(\n"
+ " other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+ " hash = (37 * hash) + $constant_name$;\n"
+ " hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
+ "}\n");
+}
+
+string ImmutableMapFieldLiteGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h
new file mode 100644
index 00000000..a09cd536
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.h
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+ explicit ImmutableMapFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableMapFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(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;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ ClassNameResolver* name_resolver_;
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 1171b718..09b0fd94 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -49,6 +49,8 @@
#include <google/protobuf/compiler/java/java_extension.h>
#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message_builder.h>
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
@@ -93,44 +95,47 @@ ImmutableMessageGenerator::ImmutableMessageGenerator(
: MessageGenerator(descriptor), context_(context),
name_resolver_(context->GetNameResolver()),
field_generators_(descriptor, context_) {
+ GOOGLE_CHECK_NE(
+ FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
}
ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
- if (HasDescriptorMethods(descriptor_)) {
- // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
- // used in the construction of descriptors, we have a tricky bootstrapping
- // problem. To help control static initialization order, we make sure all
- // descriptors and other static data that depends on them are members of
- // the outermost class in the file. This way, they will be initialized in
- // a deterministic order.
-
- map<string, string> vars;
- vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
- vars["index"] = SimpleItoa(descriptor_->index());
- vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
- if (descriptor_->containing_type() != NULL) {
- vars["parent"] = UniqueFileScopeIdentifier(
- descriptor_->containing_type());
- }
- if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
- // We can only make these package-private since the classes that use them
- // are in separate files.
- vars["private"] = "";
- } else {
- vars["private"] = "private ";
- }
+ // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
+ // used in the construction of descriptors, we have a tricky bootstrapping
+ // problem. To help control static initialization order, we make sure all
+ // descriptors and other static data that depends on them are members of
+ // the outermost class in the file. This way, they will be initialized in
+ // a deterministic order.
- // The descriptor for this type.
- printer->Print(vars,
- "$private$static final com.google.protobuf.Descriptors.Descriptor\n"
- " internal_$identifier$_descriptor;\n");
-
- // And the FieldAccessorTable.
- GenerateFieldAccessorTable(printer);
+ map<string, string> vars;
+ vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+ vars["index"] = SimpleItoa(descriptor_->index());
+ vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+ if (descriptor_->containing_type() != NULL) {
+ vars["parent"] = UniqueFileScopeIdentifier(
+ descriptor_->containing_type());
+ }
+ if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
+ // We can only make these package-private since the classes that use them
+ // are in separate files.
+ vars["private"] = "";
+ } else {
+ vars["private"] = "private ";
}
+ // The descriptor for this type.
+ printer->Print(vars,
+ // TODO(teboring): final needs to be added back. The way to fix it is to
+ // generate methods that can construct the types, and then still declare the
+ // types, and then init them in clinit with the new method calls.
+ "$private$static com.google.protobuf.Descriptors.Descriptor\n"
+ " internal_$identifier$_descriptor;\n");
+
+ // And the FieldAccessorTable.
+ GenerateFieldAccessorTable(printer);
+
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
@@ -139,39 +144,42 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
}
}
-void ImmutableMessageGenerator::GenerateStaticVariableInitializers(
+int ImmutableMessageGenerator::GenerateStaticVariableInitializers(
io::Printer* printer) {
- if (HasDescriptorMethods(descriptor_)) {
- map<string, string> vars;
- vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
- vars["index"] = SimpleItoa(descriptor_->index());
- vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
- if (descriptor_->containing_type() != NULL) {
- vars["parent"] = UniqueFileScopeIdentifier(
- descriptor_->containing_type());
- }
-
- // The descriptor for this type.
- if (descriptor_->containing_type() == NULL) {
- printer->Print(vars,
- "internal_$identifier$_descriptor =\n"
- " getDescriptor().getMessageTypes().get($index$);\n");
- } else {
- printer->Print(vars,
- "internal_$identifier$_descriptor =\n"
- " internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
- }
+ int bytecode_estimate = 0;
+ map<string, string> vars;
+ vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+ vars["index"] = SimpleItoa(descriptor_->index());
+ vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+ if (descriptor_->containing_type() != NULL) {
+ vars["parent"] = UniqueFileScopeIdentifier(
+ descriptor_->containing_type());
+ }
- // And the FieldAccessorTable.
- GenerateFieldAccessorTableInitializer(printer);
+ // The descriptor for this type.
+ if (descriptor_->containing_type() == NULL) {
+ printer->Print(vars,
+ "internal_$identifier$_descriptor =\n"
+ " getDescriptor().getMessageTypes().get($index$);\n");
+ bytecode_estimate += 30;
+ } else {
+ printer->Print(vars,
+ "internal_$identifier$_descriptor =\n"
+ " internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
+ bytecode_estimate += 30;
}
+ // And the FieldAccessorTable.
+ bytecode_estimate += GenerateFieldAccessorTableInitializer(printer);
+
// Generate static member initializers for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
- ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
- .GenerateStaticVariableInitializers(printer);
+ bytecode_estimate +=
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+ .GenerateStaticVariableInitializers(printer);
}
+ return bytecode_estimate;
}
void ImmutableMessageGenerator::
@@ -191,8 +199,9 @@ GenerateFieldAccessorTable(io::Printer* printer) {
" internal_$identifier$_fieldAccessorTable;\n");
}
-void ImmutableMessageGenerator::
+int ImmutableMessageGenerator::
GenerateFieldAccessorTableInitializer(io::Printer* printer) {
+ int bytecode_estimate = 10;
printer->Print(
"internal_$identifier$_fieldAccessorTable = new\n"
" com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
@@ -203,6 +212,7 @@ GenerateFieldAccessorTableInitializer(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bytecode_estimate += 6;
printer->Print(
"\"$field_name$\", ",
"field_name", info->capitalized_name);
@@ -210,50 +220,33 @@ GenerateFieldAccessorTableInitializer(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
const OneofGeneratorInfo* info = context_->GetOneofGeneratorInfo(oneof);
+ bytecode_estimate += 6;
printer->Print(
"\"$oneof_name$\", ",
"oneof_name", info->capitalized_name);
}
printer->Print("});\n");
+ return bytecode_estimate;
}
// ===================================================================
void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
if (descriptor_->extension_range_count() > 0) {
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public interface $classname$OrBuilder extends\n"
- " $extra_interfaces$\n"
- " com.google.protobuf.GeneratedMessage.\n"
- " ExtendableMessageOrBuilder<$classname$> {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
- } else {
- printer->Print(
- "public interface $classname$OrBuilder extends \n"
- " $extra_interfaces$\n"
- " com.google.protobuf.GeneratedMessageLite.\n"
- " ExtendableMessageOrBuilder<$classname$> {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
- }
+ printer->Print(
+ "public interface $classname$OrBuilder extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.GeneratedMessage.\n"
+ " ExtendableMessageOrBuilder<$classname$> {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name());
} else {
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public interface $classname$OrBuilder extends\n"
- " $extra_interfaces$\n"
- " com.google.protobuf.MessageOrBuilder {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
- } else {
- printer->Print(
- "public interface $classname$OrBuilder extends\n"
- " $extra_interfaces$\n"
- " com.google.protobuf.MessageLiteOrBuilder {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
- }
+ printer->Print(
+ "public interface $classname$OrBuilder extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.MessageOrBuilder {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name());
}
printer->Indent();
@@ -278,7 +271,6 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
variables["static"] = is_own_file ? " " : " static ";
variables["classname"] = descriptor_->name();
variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
- variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite";
WriteMessageDocComment(printer, descriptor_);
@@ -287,70 +279,63 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
if (descriptor_->extension_range_count() > 0) {
printer->Print(variables,
"public $static$final class $classname$ extends\n"
- " com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage<\n"
+ " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
" $classname$> implements\n"
" $extra_interfaces$\n"
" $classname$OrBuilder {\n");
builder_type = strings::Substitute(
- "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>",
- name_resolver_->GetImmutableClassName(descriptor_),
- variables["lite"]);
+ "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
+ name_resolver_->GetImmutableClassName(descriptor_));
} else {
printer->Print(variables,
"public $static$final class $classname$ extends\n"
- " com.google.protobuf.GeneratedMessage$lite$ implements\n"
+ " com.google.protobuf.GeneratedMessage implements\n"
" $extra_interfaces$\n"
" $classname$OrBuilder {\n");
- builder_type = strings::Substitute(
- "com.google.protobuf.GeneratedMessage$0.Builder",
- variables["lite"]);
+
+ builder_type = "com.google.protobuf.GeneratedMessage.Builder";
}
printer->Indent();
- if (HasDescriptorMethods(descriptor_)) {
- // 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$($buildertype$ builder) {\n"
- " super(builder);\n"
- "}\n",
- "classname", descriptor_->name(),
- "buildertype", builder_type);
- printer->Print(
- "private $classname$() {\n",
- "classname", descriptor_->name());
- printer->Indent();
- GenerateInitializers(printer);
- printer->Outdent();
- printer->Print(
- "}\n"
- "\n");
- }
+ // 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$($buildertype$ builder) {\n"
+ " super(builder);\n"
+ "}\n",
+ "classname", descriptor_->name(),
+ "buildertype", builder_type);
+ printer->Print(
+ "private $classname$() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ GenerateInitializers(printer);
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
- if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "@java.lang.Override\n"
+ "public final com.google.protobuf.UnknownFieldSet\n"
+ "getUnknownFields() {\n");
+ if (PreserveUnknownFields(descriptor_)) {
printer->Print(
- "@java.lang.Override\n"
- "public final com.google.protobuf.UnknownFieldSet\n"
- "getUnknownFields() {\n");
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print(
- " return this.unknownFields;\n");
- } else {
- printer->Print(
- " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
- }
+ " return this.unknownFields;\n");
+ } else {
printer->Print(
- "}\n");
+ " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
}
+ printer->Print(
+ "}\n");
if (HasGeneratedMethods(descriptor_)) {
GenerateParsingConstructor(printer);
}
GenerateDescriptorMethods(printer);
- GenerateParser(printer);
// Nested types
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@@ -460,7 +445,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
}
if (HasGeneratedMethods(descriptor_)) {
- GenerateIsInitialized(printer, MEMOIZE);
+ GenerateIsInitialized(printer);
GenerateMessageSerializationMethods(printer);
}
@@ -481,45 +466,33 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
// Carefully initialize the default instance in such a way that it doesn't
// conflict with other initialization.
printer->Print(
- "private static final $classname$ defaultInstance;",
+ "private static final $classname$ DEFAULT_INSTANCE;\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "static {\n"
- " defaultInstance = new $classname$();\n"
- "}\n"
- "\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- } else {
- // LITE_RUNTIME only has one constructor.
- printer->Print(
- "static {\n"
- " try {\n"
- " defaultInstance = new $classname$(\n"
- " com.google.protobuf.Internal\n"
- " .EMPTY_CODED_INPUT_STREAM,\n"
- " com.google.protobuf.ExtensionRegistryLite\n"
- " .getEmptyRegistry());\n"
- " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
- " throw new ExceptionInInitializerError(e);\n"
- " }\n"
- "}\n"
- "\n",
- "classname", descriptor_->name());
- }
+ printer->Print(
+ "static {\n"
+ " DEFAULT_INSTANCE = new $classname$();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
printer->Print(
"public static $classname$ getDefaultInstance() {\n"
- " return defaultInstance;\n"
- "}\n"
- "\n"
- "public $classname$ getDefaultInstanceForType() {\n"
- " return defaultInstance;\n"
+ " return DEFAULT_INSTANCE;\n"
"}\n"
"\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
- // Extensions must be declared after the defaultInstance is initialized
- // because the defaultInstance is used by the extension to lazily retrieve
+ GenerateParser(printer);
+
+ printer->Print(
+ "public $classname$ getDefaultInstanceForType() {\n"
+ " return DEFAULT_INSTANCE;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+ // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
// the outer class's FileDescriptor.
for (int i = 0; i < descriptor_->extension_count(); i++) {
ImmutableExtensionGenerator(descriptor_->extension(i), context_)
@@ -542,36 +515,36 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
sorted_extensions.push_back(descriptor_->extension_range(i));
}
- sort(sorted_extensions.begin(), sorted_extensions.end(),
- ExtensionRangeOrdering());
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeOrdering());
printer->Print(
"public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
" throws java.io.IOException {\n");
printer->Indent();
- // writeTo(CodedOutputStream output) might be invoked without
- // getSerializedSize() ever being called, but we need the memoized
- // sizes in case this message has packed fields. Rather than emit checks for
- // each packed field, just call getSerializedSize() up front for all messages.
- // In most cases, getSerializedSize() will have already been called anyway by
- // one of the wrapper writeTo() methods, making this call cheap.
- printer->Print(
- "getSerializedSize();\n");
+ if (HasPackedFields(descriptor_)) {
+ // writeTo(CodedOutputStream output) might be invoked without
+ // getSerializedSize() ever being called, but we need the memoized
+ // sizes in case this message has packed fields. Rather than emit checks for
+ // each packed field, just call getSerializedSize() up front.
+ // In most cases, getSerializedSize() will have already been called anyway
+ // by one of the wrapper writeTo() methods, making this call cheap.
+ printer->Print(
+ "getSerializedSize();\n");
+ }
if (descriptor_->extension_range_count() > 0) {
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
- "com.google.protobuf.GeneratedMessage$lite$\n"
- " .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
- " newMessageSetExtensionWriter();\n",
- "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
+ "com.google.protobuf.GeneratedMessage\n"
+ " .ExtendableMessage<$classname$>.ExtensionWriter\n"
+ " extensionWriter = newMessageSetExtensionWriter();\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
} else {
printer->Print(
- "com.google.protobuf.GeneratedMessage$lite$\n"
- " .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
- " newExtensionWriter();\n",
- "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
+ "com.google.protobuf.GeneratedMessage\n"
+ " .ExtendableMessage<$classname$>.ExtensionWriter\n"
+ " extensionWriter = newExtensionWriter();\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
}
}
@@ -592,8 +565,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
}
if (PreserveUnknownFields(descriptor_)) {
- if (descriptor_->options().message_set_wire_format()
- && HasDescriptorMethods(descriptor_)) {
+ if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"unknownFields.writeAsMessageSetTo(output);\n");
} else {
@@ -629,8 +601,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
}
if (PreserveUnknownFields(descriptor_)) {
- if (descriptor_->options().message_set_wire_format()
- && HasDescriptorMethods(descriptor_)) {
+ if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"size += unknownFields.getSerializedSizeAsMessageSet();\n");
} else {
@@ -727,570 +698,115 @@ void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange(
// ===================================================================
void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
+ // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+ printer->Print(
+ "public Builder newBuilderForType() { return newBuilder(); }\n");
+
printer->Print(
- "public static Builder newBuilder() { return new Builder(); }\n"
- "public Builder newBuilderForType() { return newBuilder(); }\n"
+ "public static Builder newBuilder() {\n"
+ " return DEFAULT_INSTANCE.toBuilder();\n"
+ "}\n"
"public static Builder newBuilder($classname$ prototype) {\n"
- " return newBuilder().mergeFrom(prototype);\n"
+ " return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
+ "}\n"
+ "public Builder toBuilder() {\n"
+ " return this == DEFAULT_INSTANCE\n"
+ " ? new Builder() : new Builder().mergeFrom(this);\n"
"}\n"
- "public Builder toBuilder() { return newBuilder(this); }\n"
"\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
- if (HasNestedBuilders(descriptor_)) {
- printer->Print(
- "@java.lang.Override\n"
- "protected Builder newBuilderForType(\n"
- " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
- " Builder builder = new Builder(parent);\n"
- " return builder;\n"
- "}\n");
- }
-
- WriteMessageDocComment(printer, descriptor_);
-
- if (descriptor_->extension_range_count() > 0) {
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public static final class Builder extends\n"
- " com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
- " $classname$, Builder> implements\n"
- " $extra_interfaces$\n"
- " $classname$OrBuilder {\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_),
- "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
- } else {
- printer->Print(
- "public static final class Builder extends\n"
- " com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
- " $classname$, Builder> implements\n"
- " $extra_interfaces$\n"
- " $classname$OrBuilder {\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_),
- "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
- }
- } else {
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public static final class Builder extends\n"
- " com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
- " $extra_interfaces$\n"
- " $classname$OrBuilder {\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_),
- "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
- } else {
- printer->Print(
- "public static final class Builder extends\n"
- " com.google.protobuf.GeneratedMessageLite.Builder<\n"
- " $classname$, Builder>\n"
- " implements\n"
- " $extra_interfaces$\n"
- " $classname$OrBuilder {\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_),
- "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
- }
- }
- printer->Indent();
-
- GenerateDescriptorMethods(printer);
- GenerateCommonBuilderMethods(printer);
-
- if (HasGeneratedMethods(descriptor_)) {
- GenerateIsInitialized(printer, DONT_MEMOIZE);
- GenerateBuilderParsingMethods(printer);
- }
-
- // oneof
- map<string, string> vars;
- for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- vars["oneof_name"] = context_->GetOneofGeneratorInfo(
- descriptor_->oneof_decl(i))->name;
- vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
- descriptor_->oneof_decl(i))->capitalized_name;
- vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
- // oneofCase_ and oneof_
- printer->Print(vars,
- "private int $oneof_name$Case_ = 0;\n"
- "private java.lang.Object $oneof_name$_;\n");
- // oneofCase() and clearOneof()
- printer->Print(vars,
- "public $oneof_capitalized_name$Case\n"
- " get$oneof_capitalized_name$Case() {\n"
- " return $oneof_capitalized_name$Case.valueOf(\n"
- " $oneof_name$Case_);\n"
- "}\n"
- "\n"
- "public Builder clear$oneof_capitalized_name$() {\n"
- " $oneof_name$Case_ = 0;\n"
- " $oneof_name$_ = null;\n");
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(" onChanged();\n");
- }
- printer->Print(
- " return this;\n"
- "}\n"
- "\n");
- }
-
- if (GenerateHasBits(descriptor_)) {
- // Integers for bit fields.
- int totalBits = 0;
- for (int i = 0; i < descriptor_->field_count(); i++) {
- totalBits += field_generators_.get(descriptor_->field(i))
- .GetNumBitsForBuilder();
- }
- int totalInts = (totalBits + 31) / 32;
- for (int i = 0; i < totalInts; i++) {
- printer->Print("private int $bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
- }
- }
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- printer->Print("\n");
- field_generators_.get(descriptor_->field(i))
- .GenerateBuilderMembers(printer);
- }
-
- if (!PreserveUnknownFields(descriptor_)) {
- printer->Print(
- "public final Builder setUnknownFields(\n"
- " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
- " return this;\n"
- "}\n"
- "\n"
- "public final Builder mergeUnknownFields(\n"
- " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
- " return this;\n"
- "}\n"
- "\n");
- }
-
printer->Print(
- "\n"
- "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
- "full_name", descriptor_->full_name());
-
- printer->Outdent();
- printer->Print("}\n");
+ "@java.lang.Override\n"
+ "protected Builder newBuilderForType(\n"
+ " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+ " Builder builder = new Builder(parent);\n"
+ " return builder;\n"
+ "}\n");
+
+ MessageBuilderGenerator builderGenerator(descriptor_, context_);
+ builderGenerator.Generate(printer);
}
void ImmutableMessageGenerator::
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", name_resolver_->GetImmutableClassName(descriptor_->file()),
- "identifier", UniqueFileScopeIdentifier(descriptor_));
- }
- vector<const FieldDescriptor*> map_fields;
- for (int i = 0; i < descriptor_->field_count(); i++) {
- const FieldDescriptor* field = descriptor_->field(i);
- if (GetJavaType(field) == JAVATYPE_MESSAGE &&
- IsMapEntry(field->message_type())) {
- map_fields.push_back(field);
- }
- }
- if (!map_fields.empty()) {
- printer->Print(
- "@SuppressWarnings({\"rawtypes\"})\n"
- "protected com.google.protobuf.MapField internalGetMapField(\n"
- " int number) {\n"
- " switch (number) {\n");
- printer->Indent();
- printer->Indent();
- for (int i = 0; i < map_fields.size(); ++i) {
- const FieldDescriptor* field = map_fields[i];
- const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
- printer->Print(
- "case $number$:\n"
- " return $name$_;\n",
- "number", SimpleItoa(field->number()),
- "name", info->name);
- }
- printer->Print(
- "default:\n"
- " throw new RuntimeException(\n"
- " \"Invalid map field number: \" + number);\n");
- printer->Outdent();
- printer->Outdent();
- printer->Print(
- " }\n"
- "}\n");
- }
+ if (!descriptor_->options().no_standard_descriptor_accessor()) {
printer->Print(
- "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
- " internalGetFieldAccessorTable() {\n"
- " return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
- " .ensureFieldAccessorsInitialized(\n"
- " $classname$.class, $classname$.Builder.class);\n"
+ "public static final com.google.protobuf.Descriptors.Descriptor\n"
+ " getDescriptor() {\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
"}\n"
"\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_),
"fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
"identifier", UniqueFileScopeIdentifier(descriptor_));
}
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateCommonBuilderMethods(io::Printer* printer) {
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "// Construct using $classname$.newBuilder()\n"
- "private Builder() {\n"
- " maybeForceBuilderInitialization();\n"
- "}\n"
- "\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
- printer->Print(
- "private Builder(\n"
- " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
- " super(parent);\n"
- " maybeForceBuilderInitialization();\n"
- "}\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- } else {
- // LITE runtime passes along the default instance to implement
- // getDefaultInstanceForType() at the GneratedMessageLite level.
- printer->Print(
- "// Construct using $classname$.newBuilder()\n"
- "private Builder() {\n"
- " super(defaultInstance);\n"
- " maybeForceBuilderInitialization();\n"
- "}\n"
- "\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ vector<const FieldDescriptor*> map_fields;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+ IsMapEntry(field->message_type())) {
+ map_fields.push_back(field);
+ }
}
-
-
- if (HasNestedBuilders(descriptor_)) {
+ if (!map_fields.empty()) {
printer->Print(
- "private void maybeForceBuilderInitialization() {\n"
- " if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
-
+ "@SuppressWarnings({\"rawtypes\"})\n"
+ "protected com.google.protobuf.MapField internalGetMapField(\n"
+ " int number) {\n"
+ " switch (number) {\n");
printer->Indent();
printer->Indent();
- for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->containing_oneof()) {
- field_generators_.get(descriptor_->field(i))
- .GenerateFieldBuilderInitializationCode(printer);
- }
+ for (int i = 0; i < map_fields.size(); ++i) {
+ const FieldDescriptor* field = map_fields[i];
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ printer->Print(
+ "case $number$:\n"
+ " return internalGet$capitalized_name$();\n",
+ "number", SimpleItoa(field->number()),
+ "capitalized_name", info->capitalized_name);
}
+ printer->Print(
+ "default:\n"
+ " throw new RuntimeException(\n"
+ " \"Invalid map field number: \" + number);\n");
printer->Outdent();
printer->Outdent();
-
- printer->Print(
- " }\n"
- "}\n");
- } else {
- printer->Print(
- "private void maybeForceBuilderInitialization() {\n"
- "}\n");
- }
-
- printer->Print(
- "public Builder clear() {\n"
- " super.clear();\n");
-
- printer->Indent();
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->containing_oneof()) {
- field_generators_.get(descriptor_->field(i))
- .GenerateBuilderClearCode(printer);
- }
- }
-
- for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- printer->Print(
- "$oneof_name$Case_ = 0;\n"
- "$oneof_name$_ = null;\n",
- "oneof_name", context_->GetOneofGeneratorInfo(
- descriptor_->oneof_decl(i))->name);
- }
-
- printer->Outdent();
-
- printer->Print(
- " return this;\n"
- "}\n"
- "\n");
-
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public com.google.protobuf.Descriptors.Descriptor\n"
- " getDescriptorForType() {\n"
- " return $fileclass$.internal_$identifier$_descriptor;\n"
- "}\n"
- "\n",
- "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
- "identifier", UniqueFileScopeIdentifier(descriptor_));
-
- // LITE runtime implements this in GeneratedMessageLite.
- printer->Print(
- "public $classname$ getDefaultInstanceForType() {\n"
- " return $classname$.getDefaultInstance();\n"
- "}\n"
- "\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- }
-
- // -----------------------------------------------------------------
-
- if (HasDescriptorMethods(descriptor_)) {
- // LITE implements build in GeneratedMessageLite to save methods.
- printer->Print(
- "public $classname$ build() {\n"
- " $classname$ result = buildPartial();\n"
- " if (!result.isInitialized()) {\n"
- " throw newUninitializedMessageException(result);\n"
- " }\n"
- " return result;\n"
- "}\n"
- "\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- }
-
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public $classname$ buildPartial() {\n"
- " $classname$ result = new $classname$(this);\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- } else {
- // LITE_RUNTIME only provides a single message constructor.
printer->Print(
- "public $classname$ buildPartial() {\n"
- " $classname$ result = null;\n"
- " try {\n"
- " result = new $classname$(\n"
- " com.google.protobuf.Internal\n"
- " .EMPTY_CODED_INPUT_STREAM,\n"
- " com.google.protobuf.ExtensionRegistryLite\n"
- " .getEmptyRegistry());\n"
- " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
- " throw new RuntimeException(e);\n"
" }\n"
- " result.unknownFields = this.unknownFields;\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
- if (descriptor_->extension_range_count() > 0) {
- printer->Print(
- " result.extensions = this.buildExtensions();\n");
- }
- }
-
- printer->Indent();
-
- int totalBuilderBits = 0;
- int totalMessageBits = 0;
- for (int i = 0; i < descriptor_->field_count(); i++) {
- const ImmutableFieldGenerator& field =
- field_generators_.get(descriptor_->field(i));
- totalBuilderBits += field.GetNumBitsForBuilder();
- totalMessageBits += field.GetNumBitsForMessage();
- }
- int totalBuilderInts = (totalBuilderBits + 31) / 32;
- int totalMessageInts = (totalMessageBits + 31) / 32;
-
- if (GenerateHasBits(descriptor_)) {
- // Local vars for from and to bit fields to avoid accessing the builder and
- // message over and over for these fields. Seems to provide a slight
- // perforamance improvement in micro benchmark and this is also what proto1
- // code does.
- for (int i = 0; i < totalBuilderInts; i++) {
- printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
- }
- for (int i = 0; i < totalMessageInts; i++) {
- printer->Print("int to_$bit_field_name$ = 0;\n",
- "bit_field_name", GetBitFieldName(i));
- }
- }
-
- // Output generation code for each field.
- for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
- }
-
- if (GenerateHasBits(descriptor_)) {
- // Copy the bit field results to the generated message
- for (int i = 0; i < totalMessageInts; i++) {
- printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
- }
- }
-
- for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
- "oneof_name", context_->GetOneofGeneratorInfo(
- descriptor_->oneof_decl(i))->name);
- }
-
- printer->Outdent();
-
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- " onBuilt();\n");
+ "}\n");
}
-
printer->Print(
- " return result;\n"
+ "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+ " internalGetFieldAccessorTable() {\n"
+ " return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+ " .ensureFieldAccessorsInitialized(\n"
+ " $classname$.class, $classname$.Builder.class);\n"
"}\n"
"\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
- // -----------------------------------------------------------------
-
- if (HasGeneratedMethods(descriptor_)) {
- // MergeFrom(Message other) requires the ability to distinguish the other
- // messages type by its descriptor.
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
- " if (other instanceof $classname$) {\n"
- " return mergeFrom(($classname$)other);\n"
- " } else {\n"
- " super.mergeFrom(other);\n"
- " return this;\n"
- " }\n"
- "}\n"
- "\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- }
-
- printer->Print(
- "public Builder mergeFrom($classname$ other) {\n"
- // Optimization: If other is the default instance, we know none of its
- // fields are set so we can skip the merge.
- " if (other == $classname$.getDefaultInstance()) return this;\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- printer->Indent();
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->containing_oneof()) {
- field_generators_.get(
- descriptor_->field(i)).GenerateMergingCode(printer);
- }
- }
-
- // Merge oneof fields.
- for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
- printer->Print(
- "switch (other.get$oneof_capitalized_name$Case()) {\n",
- "oneof_capitalized_name",
- context_->GetOneofGeneratorInfo(
- descriptor_->oneof_decl(i))->capitalized_name);
- printer->Indent();
- for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
- const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
- printer->Print(
- "case $field_name$: {\n",
- "field_name",
- ToUpper(field->name()));
- printer->Indent();
- field_generators_.get(field).GenerateMergingCode(printer);
- printer->Print(
- "break;\n");
- printer->Outdent();
- printer->Print(
- "}\n");
- }
- printer->Print(
- "case $cap_oneof_name$_NOT_SET: {\n"
- " break;\n"
- "}\n",
- "cap_oneof_name",
- ToUpper(context_->GetOneofGeneratorInfo(
- descriptor_->oneof_decl(i))->name));
- printer->Outdent();
- printer->Print(
- "}\n");
- }
-
- printer->Outdent();
-
- // if message type has extensions
- if (descriptor_->extension_range_count() > 0) {
- printer->Print(
- " this.mergeExtensionFields(other);\n");
- }
-
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print(
- " this.mergeUnknownFields(other.unknownFields);\n");
- }
-
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(" onChanged();\n");
- }
-
- printer->Print(
- " return this;\n"
- "}\n"
- "\n");
- }
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateBuilderParsingMethods(io::Printer* printer) {
- if (HasDescriptorMethods(descriptor_)) {
- // LITE_RUNTIME implements this at the GeneratedMessageLite level.
- printer->Print(
- "public Builder mergeFrom(\n"
- " com.google.protobuf.CodedInputStream input,\n"
- " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\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", name_resolver_->GetImmutableClassName(descriptor_));
- }
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
}
// ===================================================================
void ImmutableMessageGenerator::GenerateIsInitialized(
- io::Printer* printer, UseMemoization useMemoization) {
- bool memoization = useMemoization == MEMOIZE;
- if (memoization) {
- // Memoizes whether the protocol buffer is fully initialized (has all
- // required fields). -1 means not yet computed. 0 means false and 1 means
- // true.
- printer->Print(
- "private byte memoizedIsInitialized = -1;\n");
- }
+ io::Printer* printer) {
+ // Memoizes whether the protocol buffer is fully initialized (has all
+ // required fields). -1 means not yet computed. 0 means false and 1 means
+ // true.
+ printer->Print(
+ "private byte memoizedIsInitialized = -1;\n");
printer->Print(
"public final boolean isInitialized() {\n");
printer->Indent();
- if (memoization) {
- // Don't directly compare to -1 to avoid an Android x86 JIT bug.
- printer->Print(
- "byte isInitialized = memoizedIsInitialized;\n"
- "if (isInitialized == 1) return true;\n"
- "if (isInitialized == 0) return false;\n"
- "\n");
- }
+ // Don't directly compare to -1 to avoid an Android x86 JIT bug.
+ printer->Print(
+ "byte isInitialized = memoizedIsInitialized;\n"
+ "if (isInitialized == 1) return true;\n"
+ "if (isInitialized == 0) return false;\n"
+ "\n");
// Check that all required fields in this message are set.
// TODO(kenton): We can optimize this when we switch to putting all the
@@ -1302,11 +818,10 @@ void ImmutableMessageGenerator::GenerateIsInitialized(
if (field->is_required()) {
printer->Print(
"if (!has$name$()) {\n"
- " $memoize$\n"
+ " memoizedIsInitialized = 0;\n"
" return false;\n"
"}\n",
- "name", info->capitalized_name,
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ "name", info->capitalized_name);
}
}
@@ -1320,13 +835,12 @@ void ImmutableMessageGenerator::GenerateIsInitialized(
case FieldDescriptor::LABEL_REQUIRED:
printer->Print(
"if (!get$name$().isInitialized()) {\n"
- " $memoize$\n"
+ " memoizedIsInitialized = 0;\n"
" return false;\n"
"}\n",
"type", name_resolver_->GetImmutableClassName(
field->message_type()),
- "name", info->capitalized_name,
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ "name", info->capitalized_name);
break;
case FieldDescriptor::LABEL_OPTIONAL:
if (!SupportFieldPresence(descriptor_->file()) &&
@@ -1345,38 +859,35 @@ void ImmutableMessageGenerator::GenerateIsInitialized(
}
printer->Print(
" if (!get$name$().isInitialized()) {\n"
- " $memoize$\n"
+ " memoizedIsInitialized = 0;\n"
" return false;\n"
" }\n"
"}\n",
- "name", info->capitalized_name,
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ "name", info->capitalized_name);
break;
case FieldDescriptor::LABEL_REPEATED:
if (IsMapEntry(field->message_type())) {
printer->Print(
"for ($type$ item : get$name$().values()) {\n"
" if (!item.isInitialized()) {\n"
- " $memoize$\n"
+ " memoizedIsInitialized = 0;\n"
" return false;\n"
" }\n"
"}\n",
"type", MapValueImmutableClassdName(field->message_type(),
name_resolver_),
- "name", info->capitalized_name,
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ "name", info->capitalized_name);
} else {
printer->Print(
"for (int i = 0; i < get$name$Count(); i++) {\n"
" if (!get$name$(i).isInitialized()) {\n"
- " $memoize$\n"
+ " memoizedIsInitialized = 0;\n"
" return false;\n"
" }\n"
"}\n",
"type", name_resolver_->GetImmutableClassName(
field->message_type()),
- "name", info->capitalized_name,
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ "name", info->capitalized_name);
}
break;
}
@@ -1386,18 +897,15 @@ void ImmutableMessageGenerator::GenerateIsInitialized(
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"if (!extensionsAreInitialized()) {\n"
- " $memoize$\n"
+ " memoizedIsInitialized = 0;\n"
" return false;\n"
- "}\n",
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ "}\n");
}
printer->Outdent();
- if (memoization) {
- printer->Print(
- " memoizedIsInitialized = 1;\n");
- }
+ printer->Print(
+ " memoizedIsInitialized = 1;\n");
printer->Print(
" return true;\n"
@@ -1463,12 +971,10 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
printer->Print(
"result = result && unknownFields.equals(other.unknownFields);\n");
}
- if (HasDescriptorMethods(descriptor_)) {
- if (descriptor_->extension_range_count() > 0) {
- printer->Print(
- "result = result &&\n"
- " getExtensionFields().equals(other.getExtensionFields());\n");
- }
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "result = result &&\n"
+ " getExtensionFields().equals(other.getExtensionFields());\n");
}
printer->Print(
"return result;\n");
@@ -1491,14 +997,7 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
"}\n"
"int hash = 41;\n");
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
- } else {
- // Include the hash of the class so that two objects with different types
- // but the same field values will probably have different hashes.
- printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
- }
+ printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
@@ -1516,11 +1015,9 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
printer->Print("}\n");
}
}
- if (HasDescriptorMethods(descriptor_)) {
- if (descriptor_->extension_range_count() > 0) {
- printer->Print(
- "hash = hashFields(hash, getExtensionFields());\n");
- }
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "hash = hashFields(hash, getExtensionFields());\n");
}
printer->Print(
@@ -1558,19 +1055,13 @@ GenerateParsingConstructor(io::Printer* printer) {
printer->Print(
"private $classname$(\n"
" com.google.protobuf.CodedInputStream input,\n"
- " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
- " throws com.google.protobuf.InvalidProtocolBufferException {\n",
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
"classname", descriptor_->name());
printer->Indent();
// Initialize all fields to default.
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "this();\n");
- } else {
- // LITE_RUNTIME only has one constructor.
- GenerateInitializers(printer);
- }
+ printer->Print(
+ "this();\n");
// Use builder bits to track mutable repeated fields.
int totalBuilderBits = 0;
@@ -1586,15 +1077,9 @@ GenerateParsingConstructor(io::Printer* printer) {
}
if (PreserveUnknownFields(descriptor_)) {
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
- " com.google.protobuf.UnknownFieldSet.newBuilder();\n");
- } else {
- printer->Print(
- "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
- " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
- }
+ printer->Print(
+ "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
+ " com.google.protobuf.UnknownFieldSet.newBuilder();\n");
}
printer->Print(
@@ -1617,29 +1102,14 @@ GenerateParsingConstructor(io::Printer* printer) {
" break;\n");
if (PreserveUnknownFields(descriptor_)) {
- if (!HasDescriptorMethods(descriptor_)
- && descriptor_->extension_range_count() > 0) {
- // Lite runtime directly invokes parseUnknownField to reduce method
- // counts.
- printer->Print(
- "default: {\n"
- " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
- " input, unknownFields,\n"
- " extensionRegistry, tag)) {\n"
- " done = true;\n" // it's an endgroup tag
- " }\n"
- " break;\n"
- "}\n");
- } else {
- printer->Print(
- "default: {\n"
- " if (!parseUnknownField(input, unknownFields,\n"
- " extensionRegistry, tag)) {\n"
- " done = true;\n" // it's an endgroup tag
- " }\n"
- " break;\n"
- "}\n");
- }
+ printer->Print(
+ "default: {\n"
+ " if (!parseUnknownField(input, unknownFields,\n"
+ " extensionRegistry, tag)) {\n"
+ " done = true;\n" // it's an endgroup tag
+ " }\n"
+ " break;\n"
+ "}\n");
} else {
printer->Print(
"default: {\n"
@@ -1695,10 +1165,11 @@ GenerateParsingConstructor(io::Printer* printer) {
printer->Outdent();
printer->Print(
"} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
- " throw e.setUnfinishedMessage(this);\n"
+ " throw new RuntimeException(e.setUnfinishedMessage(this));\n"
"} catch (java.io.IOException e) {\n"
- " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
- " e.getMessage()).setUnfinishedMessage(this);\n"
+ " throw new RuntimeException(\n"
+ " new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e.getMessage()).setUnfinishedMessage(this));\n"
"} finally {\n");
printer->Indent();
@@ -1713,18 +1184,9 @@ GenerateParsingConstructor(io::Printer* printer) {
printer->Print("this.unknownFields = unknownFields.build();\n");
}
- if (!HasDescriptorMethods(descriptor_)) {
- // LITE runtime uses a static method to reduce method count.
- if (descriptor_->extension_range_count() > 0) {
- // Make extensions immutable.
- printer->Print(
- "makeExtensionsImmutable(extensions);\n");
- }
- } else {
- // Make extensions immutable.
- printer->Print(
- "makeExtensionsImmutable();\n");
- }
+ // Make extensions immutable.
+ printer->Print(
+ "makeExtensionsImmutable();\n");
printer->Outdent();
printer->Outdent();
@@ -1747,13 +1209,24 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
" throws com.google.protobuf.InvalidProtocolBufferException {\n",
"classname", descriptor_->name());
if (HasGeneratedMethods(descriptor_)) {
+ // The parsing constructor throws an InvalidProtocolBufferException via a
+ // RuntimeException to aid in method pruning. We unwrap it here.
printer->Print(
- " return new $classname$(input, extensionRegistry);\n",
+ " try {\n"
+ " return new $classname$(input, extensionRegistry);\n"
+ " } catch (RuntimeException e) {\n"
+ " if (e.getCause() instanceof\n"
+ " com.google.protobuf.InvalidProtocolBufferException) {\n"
+ " throw (com.google.protobuf.InvalidProtocolBufferException)\n"
+ " e.getCause();\n"
+ " }\n"
+ " throw e;\n"
+ " }\n",
"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.
+ // 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"
@@ -1763,7 +1236,8 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
" 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"
+ " e.getMessage()).setUnfinishedMessage(\n"
+ " builder.buildPartial());\n"
"}\n"
"return builder.buildPartial();\n");
printer->Outdent();
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 91eb2876..c3c37765 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -67,8 +67,8 @@ class MessageGenerator {
virtual void GenerateStaticVariables(io::Printer* printer) = 0;
// Output code which initializes the static variables generated by
- // GenerateStaticVariables().
- virtual void GenerateStaticVariableInitializers(io::Printer* printer) = 0;
+ // GenerateStaticVariables(). Returns an estimate of bytecode size.
+ virtual int GenerateStaticVariableInitializers(io::Printer* printer) = 0;
// Generate the class itself.
virtual void Generate(io::Printer* printer) = 0;
@@ -97,16 +97,16 @@ class ImmutableMessageGenerator : public MessageGenerator {
virtual void GenerateInterface(io::Printer* printer);
virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
virtual void GenerateStaticVariables(io::Printer* printer);
- virtual void GenerateStaticVariableInitializers(io::Printer* printer);
+
+ // Returns an estimate of the number of bytes the printed code will compile to
+ virtual int GenerateStaticVariableInitializers(io::Printer* printer);
private:
- enum UseMemoization {
- MEMOIZE,
- DONT_MEMOIZE
- };
void GenerateFieldAccessorTable(io::Printer* printer);
- void GenerateFieldAccessorTableInitializer(io::Printer* printer);
+
+ // Returns an estimate of the number of bytes the printed code will compile to
+ int GenerateFieldAccessorTableInitializer(io::Printer* printer);
void GenerateMessageSerializationMethods(io::Printer* printer);
void GenerateParseFromMethods(io::Printer* printer);
@@ -116,11 +116,8 @@ class ImmutableMessageGenerator : public MessageGenerator {
io::Printer* printer, const Descriptor::ExtensionRange* range);
void GenerateBuilder(io::Printer* printer);
- void GenerateCommonBuilderMethods(io::Printer* printer);
+ void GenerateIsInitialized(io::Printer* printer);
void GenerateDescriptorMethods(io::Printer* printer);
- void GenerateBuilderParsingMethods(io::Printer* printer);
- void GenerateIsInitialized(io::Printer* printer,
- UseMemoization useMemoization);
void GenerateInitializers(io::Printer* printer);
void GenerateEqualsAndHashCode(io::Printer* printer);
void GenerateParser(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
new file mode 100644
index 00000000..72694119
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -0,0 +1,661 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: dweis@google.com (Daniel Weis)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_builder.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#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_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.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 {
+namespace compiler {
+namespace java {
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+ return SupportFieldPresence(descriptor->file()) ||
+ HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+ ClassNameResolver* name_resolver) {
+ const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+ return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+} // namespace
+
+MessageBuilderGenerator::MessageBuilderGenerator(
+ const Descriptor* descriptor, Context* context)
+ : descriptor_(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()),
+ field_generators_(descriptor, context_) {
+ GOOGLE_CHECK_NE(
+ FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+MessageBuilderGenerator::~MessageBuilderGenerator() {}
+
+void MessageBuilderGenerator::
+Generate(io::Printer* printer) {
+ WriteMessageDocComment(printer, descriptor_);
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "public static final class Builder extends\n"
+ " com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
+ " $classname$, Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+ } else {
+ printer->Print(
+ "public static final class Builder extends\n"
+ " com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+ }
+ printer->Indent();
+
+ GenerateDescriptorMethods(printer);
+ GenerateCommonBuilderMethods(printer);
+
+ if (HasGeneratedMethods(descriptor_)) {
+ GenerateIsInitialized(printer);
+ GenerateBuilderParsingMethods(printer);
+ }
+
+ // oneof
+ map<string, string> vars;
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name;
+ vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name;
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ // oneofCase_ and oneof_
+ printer->Print(vars,
+ "private int $oneof_name$Case_ = 0;\n"
+ "private java.lang.Object $oneof_name$_;\n");
+ // oneofCase() and clearOneof()
+ printer->Print(vars,
+ "public $oneof_capitalized_name$Case\n"
+ " get$oneof_capitalized_name$Case() {\n"
+ " return $oneof_capitalized_name$Case.valueOf(\n"
+ " $oneof_name$Case_);\n"
+ "}\n"
+ "\n"
+ "public Builder clear$oneof_capitalized_name$() {\n"
+ " $oneof_name$Case_ = 0;\n"
+ " $oneof_name$_ = null;\n");
+ printer->Print(" onChanged();\n");
+ printer->Print(
+ " return this;\n"
+ "}\n"
+ "\n");
+ }
+
+ if (GenerateHasBits(descriptor_)) {
+ // Integers for bit fields.
+ int totalBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ totalBits += field_generators_.get(descriptor_->field(i))
+ .GetNumBitsForBuilder();
+ }
+ int totalInts = (totalBits + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateBuilderMembers(printer);
+ }
+
+ if (!PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ "public final Builder setUnknownFields(\n"
+ " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+ " return this;\n"
+ "}\n"
+ "\n"
+ "public final Builder mergeUnknownFields(\n"
+ " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+ " return this;\n"
+ "}\n"
+ "\n");
+ }
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateDescriptorMethods(io::Printer* printer) {
+ 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", name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+ }
+ vector<const FieldDescriptor*> map_fields;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+ IsMapEntry(field->message_type())) {
+ map_fields.push_back(field);
+ }
+ }
+ if (!map_fields.empty()) {
+ printer->Print(
+ "@SuppressWarnings({\"rawtypes\"})\n"
+ "protected com.google.protobuf.MapField internalGetMapField(\n"
+ " int number) {\n"
+ " switch (number) {\n");
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < map_fields.size(); ++i) {
+ const FieldDescriptor* field = map_fields[i];
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ printer->Print(
+ "case $number$:\n"
+ " return internalGet$capitalized_name$();\n",
+ "number", SimpleItoa(field->number()),
+ "capitalized_name", info->capitalized_name);
+ }
+ printer->Print(
+ "default:\n"
+ " throw new RuntimeException(\n"
+ " \"Invalid map field number: \" + number);\n");
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n"
+ "}\n");
+ printer->Print(
+ "@SuppressWarnings({\"rawtypes\"})\n"
+ "protected com.google.protobuf.MapField internalGetMutableMapField(\n"
+ " int number) {\n"
+ " switch (number) {\n");
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < map_fields.size(); ++i) {
+ const FieldDescriptor* field = map_fields[i];
+ const FieldGeneratorInfo* info =
+ context_->GetFieldGeneratorInfo(field);
+ printer->Print(
+ "case $number$:\n"
+ " return internalGetMutable$capitalized_name$();\n",
+ "number", SimpleItoa(field->number()),
+ "capitalized_name", info->capitalized_name);
+ }
+ printer->Print(
+ "default:\n"
+ " throw new RuntimeException(\n"
+ " \"Invalid map field number: \" + number);\n");
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n"
+ "}\n");
+ }
+ printer->Print(
+ "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+ " internalGetFieldAccessorTable() {\n"
+ " return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+ " .ensureFieldAccessorsInitialized(\n"
+ " $classname$.class, $classname$.Builder.class);\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
+ printer->Print(
+ "// Construct using $classname$.newBuilder()\n"
+ "private Builder() {\n"
+ " maybeForceBuilderInitialization();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "private Builder(\n"
+ " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+ " super(parent);\n"
+ " maybeForceBuilderInitialization();\n"
+ "}\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "private void maybeForceBuilderInitialization() {\n"
+ " if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
+
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateFieldBuilderInitializationCode(printer);
+ }
+ }
+ printer->Outdent();
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ "}\n");
+
+ printer->Print(
+ "public Builder clear() {\n"
+ " super.clear();\n");
+
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateBuilderClearCode(printer);
+ }
+ }
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "$oneof_name$Case_ = 0;\n"
+ "$oneof_name$_ = null;\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ " return this;\n"
+ "}\n"
+ "\n");
+
+ printer->Print(
+ "public com.google.protobuf.Descriptors.Descriptor\n"
+ " getDescriptorForType() {\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
+ "}\n"
+ "\n",
+ "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+
+ // LITE runtime implements this in GeneratedMessageLite.
+ printer->Print(
+ "public $classname$ getDefaultInstanceForType() {\n"
+ " return $classname$.getDefaultInstance();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "public $classname$ build() {\n"
+ " $classname$ result = buildPartial();\n"
+ " if (!result.isInitialized()) {\n"
+ " throw newUninitializedMessageException(result);\n"
+ " }\n"
+ " return result;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "public $classname$ buildPartial() {\n"
+ " $classname$ result = new $classname$(this);\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Indent();
+
+ int totalBuilderBits = 0;
+ int totalMessageBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const ImmutableFieldGenerator& field =
+ field_generators_.get(descriptor_->field(i));
+ totalBuilderBits += field.GetNumBitsForBuilder();
+ totalMessageBits += field.GetNumBitsForMessage();
+ }
+ int totalBuilderInts = (totalBuilderBits + 31) / 32;
+ int totalMessageInts = (totalMessageBits + 31) / 32;
+
+ if (GenerateHasBits(descriptor_)) {
+ // Local vars for from and to bit fields to avoid accessing the builder and
+ // message over and over for these fields. Seems to provide a slight
+ // perforamance improvement in micro benchmark and this is also what proto1
+ // code does.
+ for (int i = 0; i < totalBuilderInts; i++) {
+ printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ for (int i = 0; i < totalMessageInts; i++) {
+ printer->Print("int to_$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ // Output generation code for each field.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
+ }
+
+ if (GenerateHasBits(descriptor_)) {
+ // Copy the bit field results to the generated message
+ for (int i = 0; i < totalMessageInts; i++) {
+ printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ " onBuilt();\n");
+
+ printer->Print(
+ " return result;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ // -----------------------------------------------------------------
+
+ if (HasGeneratedMethods(descriptor_)) {
+ printer->Print(
+ "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
+ " if (other instanceof $classname$) {\n"
+ " return mergeFrom(($classname$)other);\n"
+ " } else {\n"
+ " super.mergeFrom(other);\n"
+ " return this;\n"
+ " }\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "public Builder mergeFrom($classname$ other) {\n"
+ // Optimization: If other is the default instance, we know none of its
+ // fields are set so we can skip the merge.
+ " if (other == $classname$.getDefaultInstance()) return this;\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(
+ descriptor_->field(i)).GenerateMergingCode(printer);
+ }
+ }
+
+ // Merge oneof fields.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+ printer->Print(
+ "switch (other.get$oneof_capitalized_name$Case()) {\n",
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name);
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "case $field_name$: {\n",
+ "field_name",
+ ToUpper(field->name()));
+ printer->Indent();
+ field_generators_.get(field).GenerateMergingCode(printer);
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ printer->Print(
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "cap_oneof_name",
+ ToUpper(context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name));
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+
+ printer->Outdent();
+
+ // if message type has extensions
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ " this.mergeExtensionFields(other);\n");
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ " this.mergeUnknownFields(other.unknownFields);\n");
+ }
+
+ printer->Print(
+ " onChanged();\n");
+
+ printer->Print(
+ " return this;\n"
+ "}\n"
+ "\n");
+ }
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateBuilderParsingMethods(io::Printer* printer) {
+ printer->Print(
+ "public Builder mergeFrom(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\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", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::GenerateIsInitialized(
+ io::Printer* printer) {
+ printer->Print(
+ "public final boolean isInitialized() {\n");
+ printer->Indent();
+
+ // Check that all required fields in this message are set.
+ // TODO(kenton): We can optimize this when we switch to putting all the
+ // "has" fields into a single bitfield.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+
+ if (field->is_required()) {
+ printer->Print(
+ "if (!has$name$()) {\n"
+ " return false;\n"
+ "}\n",
+ "name", info->capitalized_name);
+ }
+ }
+
+ // Now check that all embedded messages are initialized.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+ HasRequiredFields(field->message_type())) {
+ switch (field->label()) {
+ case FieldDescriptor::LABEL_REQUIRED:
+ printer->Print(
+ "if (!get$name$().isInitialized()) {\n"
+ " return false;\n"
+ "}\n",
+ "type", name_resolver_->GetImmutableClassName(
+ field->message_type()),
+ "name", info->capitalized_name);
+ break;
+ case FieldDescriptor::LABEL_OPTIONAL:
+ if (!SupportFieldPresence(descriptor_->file()) &&
+ field->containing_oneof() != NULL) {
+ const OneofDescriptor* oneof = field->containing_oneof();
+ const OneofGeneratorInfo* oneof_info =
+ context_->GetOneofGeneratorInfo(oneof);
+ printer->Print(
+ "if ($oneof_name$Case_ == $field_number$) {\n",
+ "oneof_name", oneof_info->name,
+ "field_number", SimpleItoa(field->number()));
+ } else {
+ printer->Print(
+ "if (has$name$()) {\n",
+ "name", info->capitalized_name);
+ }
+ printer->Print(
+ " if (!get$name$().isInitialized()) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n",
+ "name", info->capitalized_name);
+ break;
+ case FieldDescriptor::LABEL_REPEATED:
+ if (IsMapEntry(field->message_type())) {
+ printer->Print(
+ "for ($type$ item : get$name$().values()) {\n"
+ " if (!item.isInitialized()) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n",
+ "type", MapValueImmutableClassdName(field->message_type(),
+ name_resolver_),
+ "name", info->capitalized_name);
+ } else {
+ printer->Print(
+ "for (int i = 0; i < get$name$Count(); i++) {\n"
+ " if (!get$name$(i).isInitialized()) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n",
+ "type", name_resolver_->GetImmutableClassName(
+ field->message_type()),
+ "name", info->capitalized_name);
+ }
+ break;
+ }
+ }
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "if (!extensionsAreInitialized()) {\n"
+ " return false;\n"
+ "}\n");
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ " return true;\n"
+ "}\n"
+ "\n");
+}
+
+// ===================================================================
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_builder.h b/src/google/protobuf/compiler/java/java_message_builder.h
new file mode 100644
index 00000000..015ea062
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.h
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: dweis@google.com (Daniel Weis)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageBuilderGenerator {
+ public:
+ explicit MessageBuilderGenerator(const Descriptor* descriptor,
+ Context* context);
+ virtual ~MessageBuilderGenerator();
+
+ virtual void Generate(io::Printer* printer);
+
+ private:
+ void GenerateCommonBuilderMethods(io::Printer* printer);
+ void GenerateDescriptorMethods(io::Printer* printer);
+ void GenerateBuilderParsingMethods(io::Printer* printer);
+ void GenerateIsInitialized(io::Printer* printer);
+
+ const Descriptor* descriptor_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ FieldGeneratorMap<ImmutableFieldGenerator> field_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
new file mode 100644
index 00000000..8719d00d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -0,0 +1,192 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: dweis@google.com (Daniel Weis)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#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_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.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 {
+namespace compiler {
+namespace java {
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+ return SupportFieldPresence(descriptor->file()) ||
+ HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+ ClassNameResolver* name_resolver) {
+ const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+ return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+} // namespace
+
+MessageBuilderLiteGenerator::MessageBuilderLiteGenerator(
+ const Descriptor* descriptor, Context* context)
+ : descriptor_(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()),
+ field_generators_(descriptor, context_) {
+ GOOGLE_CHECK_EQ(
+ FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {}
+
+void MessageBuilderLiteGenerator::
+Generate(io::Printer* printer) {
+ WriteMessageDocComment(printer, descriptor_);
+ printer->Print(
+ "public static final class Builder extends\n"
+ " com.google.protobuf.GeneratedMessageLite.$extendible$Builder<\n"
+ " $classname$, Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_),
+ "extendible",
+ descriptor_->extension_range_count() > 0 ? "Extendable" : "");
+ printer->Indent();
+
+ GenerateCommonBuilderMethods(printer);
+
+ // oneof
+ map<string, string> vars;
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name;
+ vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name;
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+
+ // oneofCase() and clearOneof()
+ printer->Print(vars,
+ "public $oneof_capitalized_name$Case\n"
+ " get$oneof_capitalized_name$Case() {\n"
+ " return instance.get$oneof_capitalized_name$Case();\n"
+ "}\n"
+ "\n"
+ "public Builder clear$oneof_capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$oneof_capitalized_name$();\n"
+ " return this;\n"
+ "}\n"
+ "\n");
+ }
+
+ if (GenerateHasBits(descriptor_)) {
+ // Integers for bit fields.
+ int totalBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ totalBits += field_generators_.get(descriptor_->field(i))
+ .GetNumBitsForBuilder();
+ }
+ int totalInts = (totalBits + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateBuilderMembers(printer);
+ }
+
+ if (!PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ "public final Builder setUnknownFields(\n"
+ " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+ " return this;\n"
+ "}\n"
+ "\n"
+ "public final Builder mergeUnknownFields(\n"
+ " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+ " return this;\n"
+ "}\n"
+ "\n");
+ }
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderLiteGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
+ printer->Print(
+ "// Construct using $classname$.newBuilder()\n"
+ "private Builder() {\n"
+ " super(DEFAULT_INSTANCE);\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.h b/src/google/protobuf/compiler/java/java_message_builder_lite.h
new file mode 100644
index 00000000..8597b2e6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.h
@@ -0,0 +1,83 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: dweis@google.com (Daniel Weis)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageBuilderLiteGenerator {
+ public:
+ explicit MessageBuilderLiteGenerator(const Descriptor* descriptor,
+ Context* context);
+ virtual ~MessageBuilderLiteGenerator();
+
+ virtual void Generate(io::Printer* printer);
+
+ private:
+ void GenerateCommonBuilderMethods(io::Printer* printer);
+
+ const Descriptor* descriptor_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 538f1248..b180b4a7 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -157,11 +157,9 @@ GenerateInterfaceMembers(io::Printer* printer) const {
printer->Print(variables_,
"$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");
- }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
}
void ImmutableMessageFieldGenerator::
@@ -182,14 +180,12 @@ GenerateMembers(io::Printer* printer) const {
" return $name$_ == null ? $type$.getDefaultInstance() : $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$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
- "}\n");
- }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder "
+ "get$capitalized_name$OrBuilder() {\n"
+ " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+ "}\n");
} else {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
@@ -202,14 +198,12 @@ GenerateMembers(io::Printer* printer) const {
" return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
"}\n");
- if (HasNestedBuilders(descriptor_->containing_type())) {
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$public $type$OrBuilder "
- "get$capitalized_name$OrBuilder() {\n"
- " return get$capitalized_name$();\n"
- "}\n");
- }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder "
+ "get$capitalized_name$OrBuilder() {\n"
+ " return get$capitalized_name$();\n"
+ "}\n");
}
}
@@ -217,19 +211,15 @@ void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
io::Printer* printer,
const char* regular_case,
const char* nested_builder_case) const {
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_, "if ($name$Builder_ == null) {\n");
- printer->Indent();
- printer->Print(variables_, regular_case);
- printer->Outdent();
- printer->Print("} else {\n");
- printer->Indent();
- printer->Print(variables_, nested_builder_case);
- printer->Outdent();
- printer->Print("}\n");
- } else {
- printer->Print(variables_, regular_case);
- }
+ printer->Print(variables_, "if ($name$Builder_ == null) {\n");
+ printer->Indent();
+ printer->Print(variables_, regular_case);
+ printer->Outdent();
+ printer->Print("} else {\n");
+ printer->Indent();
+ printer->Print(variables_, nested_builder_case);
+ printer->Outdent();
+ printer->Print("}\n");
}
void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
@@ -260,14 +250,12 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
"private $type$ $name$_ = null;\n");
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_,
+ printer->Print(variables_,
// If this builder is non-null, it is used and the other fields are
// ignored.
"private com.google.protobuf.SingleFieldBuilder<\n"
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
"\n");
- }
// The comments above the methods below are based on a hypothetical
// field of type "Field" called "Field".
@@ -368,40 +356,38 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$clear_has_field_bit_builder$\n"
"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");
- 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$_ == null ?\n"
- " $type$.getDefaultInstance() : $name$_;\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"
- " if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder>(\n"
- " get$capitalized_name$(),\n"
- " getParentForChildren(),\n"
- " isClean());\n"
- " $name$_ = null;\n"
- " }\n"
- " return $name$Builder_;\n"
- "}\n");
- }
+ 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");
+ 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$_ == null ?\n"
+ " $type$.getDefaultInstance() : $name$_;\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"
+ " if ($name$Builder_ == null) {\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " get$capitalized_name$(),\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $name$_ = null;\n"
+ " }\n"
+ " return $name$Builder_;\n"
+ "}\n");
}
void ImmutableMessageFieldGenerator::
@@ -557,16 +543,14 @@ GenerateMembers(io::Printer* printer) const {
" return $type$.getDefaultInstance();\n"
"}\n");
- if (HasNestedBuilders(descriptor_->containing_type())) {
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
- " if ($has_oneof_case_message$) {\n"
- " return ($type$) $oneof_name$_;\n"
- " }\n"
- " return $type$.getDefaultInstance();\n"
- "}\n");
- }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) $oneof_name$_;\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
}
void ImmutableMessageOneofFieldGenerator::
@@ -574,14 +558,12 @@ GenerateBuilderMembers(io::Printer* printer) const {
// When using nested-builders, the code initially works just like the
// non-nested builder case. It only creates a nested builder lazily on
// demand and then forever delegates to it after creation.
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_,
- // If this builder is non-null, it is used and the other fields are
- // ignored.
- "private com.google.protobuf.SingleFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
- "\n");
- }
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+ "\n");
// The comments above the methods below are based on a hypothetical
// field of type "Field" called "Field".
@@ -683,44 +665,43 @@ 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"
- " return get$capitalized_name$FieldBuilder().getBuilder();\n"
- "}\n");
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
- " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
- " return $name$Builder_.getMessageOrBuilder();\n"
- " } else {\n"
- " if ($has_oneof_case_message$) {\n"
- " return ($type$) $oneof_name$_;\n"
- " }\n"
- " return $type$.getDefaultInstance();\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"
- " if ($name$Builder_ == null) {\n"
- " if (!($has_oneof_case_message$)) {\n"
- " $oneof_name$_ = $type$.getDefaultInstance();\n"
- " }\n"
- " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder>(\n"
- " ($type$) $oneof_name$_,\n"
- " getParentForChildren(),\n"
- " isClean());\n"
- " $oneof_name$_ = null;\n"
- " }\n"
- " $set_oneof_case_message$;\n"
- " return $name$Builder_;\n"
- "}\n");
- }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+ " return get$capitalized_name$FieldBuilder().getBuilder();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
+ " return $name$Builder_.getMessageOrBuilder();\n"
+ " } else {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) $oneof_name$_;\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\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"
+ " if ($name$Builder_ == null) {\n"
+ " if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = $type$.getDefaultInstance();\n"
+ " }\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " ($type$) $oneof_name$_,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ " $set_oneof_case_message$;\n"
+ " $on_changed$;\n"
+ " return $name$Builder_;\n"
+ "}\n");
}
void ImmutableMessageOneofFieldGenerator::
@@ -830,16 +811,15 @@ GenerateInterfaceMembers(io::Printer* printer) const {
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");
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
- " int index);\n");
- }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<? extends $type$OrBuilder> \n"
+ " get$capitalized_name$OrBuilderList();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
+ " int index);\n");
}
void RepeatedImmutableMessageFieldGenerator::
@@ -881,19 +861,15 @@ void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
io::Printer* printer,
const char* regular_case,
const char* nested_builder_case) const {
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_, "if ($name$Builder_ == null) {\n");
- printer->Indent();
- printer->Print(variables_, regular_case);
- printer->Outdent();
- printer->Print("} else {\n");
- printer->Indent();
- printer->Print(variables_, nested_builder_case);
- printer->Outdent();
- printer->Print("}\n");
- } else {
- printer->Print(variables_, regular_case);
- }
+ printer->Print(variables_, "if ($name$Builder_ == null) {\n");
+ printer->Indent();
+ printer->Print(variables_, regular_case);
+ printer->Outdent();
+ printer->Print("} else {\n");
+ printer->Indent();
+ printer->Print(variables_, nested_builder_case);
+ printer->Outdent();
+ printer->Print("}\n");
}
void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
@@ -941,14 +917,12 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n"
"\n");
- if (HasNestedBuilders(descriptor_->containing_type())) {
- printer->Print(variables_,
- // If this builder is non-null, it is used and the other fields are
- // ignored.
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
- "\n");
- }
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+ "\n");
// The comments above the methods below are based on a hypothetical
// repeated field of type "Field" called "RepeatedField".
@@ -1115,70 +1089,68 @@ 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");
+ 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");
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
- " int index) {\n"
- " if ($name$Builder_ == null) {\n"
- " return $name$_.get(index);"
- " } else {\n"
- " return $name$Builder_.getMessageOrBuilder(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"
+ " return $name$_.get(index);"
+ " } else {\n"
+ " return $name$Builder_.getMessageOrBuilder(index);\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"
- " return $name$Builder_.getMessageOrBuilderList();\n"
- " } else {\n"
- " return java.util.Collections.unmodifiableList($name$_);\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"
+ " return $name$Builder_.getMessageOrBuilderList();\n"
+ " } else {\n"
+ " return java.util.Collections.unmodifiableList($name$_);\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");
- 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");
- 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"
- "}\n"
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder> \n"
- " get$capitalized_name$FieldBuilder() {\n"
- " if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
- " $type$, $type$.Builder, $type$OrBuilder>(\n"
- " $name$_,\n"
- " $get_mutable_bit_builder$,\n"
- " getParentForChildren(),\n"
- " isClean());\n"
- " $name$_ = null;\n"
- " }\n"
- " return $name$Builder_;\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");
+ 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");
+ 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"
+ "}\n"
+ "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> \n"
+ " get$capitalized_name$FieldBuilder() {\n"
+ " if ($name$Builder_ == null) {\n"
+ " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " $name$_,\n"
+ " $get_mutable_bit_builder$,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $name$_ = null;\n"
+ " }\n"
+ " return $name$Builder_;\n"
+ "}\n");
}
void RepeatedImmutableMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
new file mode 100644
index 00000000..8332202c
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -0,0 +1,944 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
+ map<string, string>* variables) {
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] =
+ name_resolver->GetImmutableClassName(descriptor->message_type());
+ (*variables)["mutable_type"] =
+ name_resolver->GetMutableClassName(descriptor->message_type());
+ (*variables)["group_or_message"] =
+ (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ?
+ "Group" : "Message";
+ // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+ // by the proto compiler
+ (*variables)["deprecation"] = descriptor->options().deprecated()
+ ? "@java.lang.Deprecated " : "";
+ (*variables)["on_changed"] =
+ HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["clear_has_field_bit_message"] =
+ GenerateClearBit(messageBitIndex) + ";";
+
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["clear_has_field_bit_message"] = "";
+
+ (*variables)["is_field_present_message"] =
+ (*variables)["name"] + "_ != null";
+ }
+
+ // For repeated builders, the underlying list tracks mutability state.
+ (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+ (*variables)["get_has_field_bit_from_local"] =
+ GenerateGetBitFromLocal(builderBitIndex);
+ (*variables)["set_has_field_bit_to_local"] =
+ GenerateSetBitToLocal(messageBitIndex);
+}
+
+} // namespace
+
+// ===================================================================
+
+ImmutableMessageFieldLiteGenerator::
+ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 1;
+}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ // TODO(jonp): In the future, consider having a method specific to the
+ // 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.
+ if (SupportFieldPresence(descriptor_->file()) ||
+ descriptor_->containing_oneof() == NULL) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private $type$ $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ 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$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+ "}\n");
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $name$_ != null;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+ "}\n");
+ }
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " $name$_ = value;\n"
+ " $set_has_field_bit_message$\n"
+ " }\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " $name$_ = builderForValue.build();\n"
+ " $set_has_field_bit_message$\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void merge$capitalized_name$($type$ value) {\n"
+ " if ($name$_ != null &&\n"
+ " $name$_ != $type$.getDefaultInstance()) {\n"
+ " $name$_ =\n"
+ " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+ " } else {\n"
+ " $name$_ = value;\n"
+ " }\n"
+ " $set_has_field_bit_message$\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {"
+ " $name$_ = null;\n"
+ " $clear_has_field_bit_message$\n"
+ "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // The comments above the methods below are based on a hypothetical
+ // field of type "Field" called "Field".
+
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+
+ // Field getField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ " }\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.merge$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "get$capitalized_name$FieldBuilder();\n");
+ }
+}
+
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " merge$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ // noop for scalars
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$type$.Builder subBuilder = null;\n"
+ "if ($is_field_present_message$) {\n"
+ " subBuilder = $name$_.toBuilder();\n"
+ "}\n");
+
+ if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "$name$_ = input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry);\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+ }
+
+ printer->Print(variables_,
+ "if (subBuilder != null) {\n"
+ " subBuilder.mergeFrom($name$_);\n"
+ " $name$_ = subBuilder.buildPartial();\n"
+ "}\n"
+ "$set_has_field_bit_message$\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for messages.
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " output.write$group_or_message$($number$, get$capitalized_name$());\n"
+ "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
+ "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$()\n"
+ " .equals(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "hash = (37 * hash) + $constant_name$;\n"
+ "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+string ImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+ImmutableMessageOneofFieldLiteGenerator::
+ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableMessageFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableMessageOneofFieldLiteGenerator::
+~ImmutableMessageOneofFieldLiteGenerator() {}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) $oneof_name$_;\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " $oneof_name$_ = value;\n"
+ " $set_oneof_case_message$;\n"
+ "}\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " $oneof_name$_ = builderForValue.build();\n"
+ " $set_oneof_case_message$;\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void merge$capitalized_name$($type$ value) {\n"
+ " if ($has_oneof_case_message$ &&\n"
+ " $oneof_name$_ != $type$.getDefaultInstance()) {\n"
+ " $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n"
+ " .mergeFrom(value).buildPartial();\n"
+ " } else {\n"
+ " $oneof_name$_ = value;\n"
+ " }\n"
+ " $set_oneof_case_message$;\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // The comments above the methods below are based on a hypothetical
+ // field of type "Field" called "Field".
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+
+ // Field getField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.merge$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "merge$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$type$.Builder subBuilder = null;\n"
+ "if ($has_oneof_case_message$) {\n"
+ " subBuilder = (($type$) $oneof_name$_).toBuilder();\n"
+ "}\n");
+
+ if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry);\n");
+ } else {
+ printer->Print(variables_,
+ "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+ }
+
+ printer->Print(variables_,
+ "if (subBuilder != null) {\n"
+ " subBuilder.mergeFrom(($type$) $oneof_name$_);\n"
+ " $oneof_name$_ = subBuilder.buildPartial();\n"
+ "}\n");
+ printer->Print(variables_,
+ "$set_oneof_case_message$;\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n"
+ "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n"
+ "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableMessageFieldLiteGenerator::
+RepeatedImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+RepeatedImmutableMessageFieldLiteGenerator::
+~RepeatedImmutableMessageFieldLiteGenerator() {}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 0;
+}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ // TODO(jonp): In the future, consider having methods specific to the
+ // 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");
+ 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");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private com.google.protobuf.Internal.ProtobufList<$type$> $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return $name$_;\n" // note: unmodifiable list
+ "}\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");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return $name$_.size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return $name$_.get(index);\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"
+ "}\n");
+
+ printer->Print(variables_,
+ "private void ensure$capitalized_name$IsMutable() {\n"
+ " if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList($name$_);\n"
+ " }\n"
+ "}\n"
+ "\n");
+
+ // Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, value);\n"
+ "}\n");
+
+ // Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, builderForValue.build());\n"
+ "}\n");
+
+ // Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(value);\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(index, value);\n"
+ "}\n");
+ // Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(builderForValue.build());\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(index, builderForValue.build());\n"
+ "}\n");
+
+ // Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " com.google.protobuf.AbstractMessageLite.addAll(\n"
+ " values, $name$_);\n"
+ "}\n");
+
+ // Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $name$_ = emptyProtobufList();\n"
+ "}\n");
+
+ // Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void remove$capitalized_name$(int index) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.remove(index);\n"
+ "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // The comments above the methods below are based on a hypothetical
+ // repeated field of type "Field" called "RepeatedField".
+
+ // List<Field> getRepeatedFieldList()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return java.util.Collections.unmodifiableList(\n"
+ " instance.get$capitalized_name$List());\n"
+ "}\n");
+
+ // int getRepeatedFieldCount()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return instance.get$capitalized_name$Count();\n"
+ "}");
+
+ // Field getRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return instance.get$capitalized_name$(index);\n"
+ "}\n");
+
+ // Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+ // Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(index, builderForValue);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " copyOnWrite();\n"
+ " instance.addAll$capitalized_name$(values);\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+
+ // Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder remove$capitalized_name$(int index) {\n"
+ " copyOnWrite();\n"
+ " instance.remove$capitalized_name$(index);\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "get$capitalized_name$FieldBuilder();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // The code below does two optimizations (non-nested builder case):
+ // 1. If the other list is empty, there's nothing to do. This ensures we
+ // don't allocate a new array if we already have an immutable one.
+ // 2. If the other list is non-empty and our current list is empty, we can
+ // reuse the other list which is guaranteed to be immutable.
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if ($name$_.isEmpty()) {\n"
+ " $name$_ = other.$name$_;\n"
+ " } else {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.addAll(other.$name$_);\n"
+ " }\n"
+ " $on_changed$\n"
+ "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!$is_mutable$) {\n"
+ " $name$_ = newProtobufList();\n"
+ "}\n");
+
+ if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "$name$_.add(input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry));\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n");
+ }
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_mutable$) {\n"
+ " $name$_.makeImmutable();\n"
+ "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.write$group_or_message$($number$, $name$_.get(i));\n"
+ "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$group_or_message$Size($number$, $name$_.get(i));\n"
+ "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$List()\n"
+ " .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (get$capitalized_name$Count() > 0) {\n"
+ " hash = (37 * hash) + $constant_name$;\n"
+ " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+ "}\n");
+}
+
+string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h
new file mode 100644
index 00000000..ae26c06a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.h
@@ -0,0 +1,157 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+ explicit ImmutableMessageFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableMessageFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(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;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ protected:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator);
+};
+
+class ImmutableMessageOneofFieldLiteGenerator
+ : public ImmutableMessageFieldLiteGenerator {
+ public:
+ ImmutableMessageOneofFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableMessageOneofFieldLiteGenerator();
+
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableMessageFieldLiteGenerator
+ : public ImmutableFieldLiteGenerator {
+ public:
+ explicit RepeatedImmutableMessageFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableMessageFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(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;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ protected:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
new file mode 100644
index 00000000..3accee92
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -0,0 +1,1174 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: dweis@google.com (Daniel Weis)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_lite.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#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_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message_builder.h>
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.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 {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+ return SupportFieldPresence(descriptor->file()) ||
+ HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+ ClassNameResolver* name_resolver) {
+ const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+ return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+} // namespace
+
+// ===================================================================
+ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator(
+ const Descriptor* descriptor, Context* context)
+ : MessageGenerator(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()),
+ field_generators_(descriptor, context_) {
+ GOOGLE_CHECK_EQ(
+ FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
+
+void ImmutableMessageLiteGenerator::GenerateStaticVariables(
+ io::Printer* printer) {
+ // Generate static members for all nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateStaticVariables(printer);
+ }
+}
+
+int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers(
+ io::Printer* printer) {
+ int bytecode_estimate = 0;
+ // Generate static member initializers for all nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ bytecode_estimate +=
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateStaticVariableInitializers(printer);
+ }
+ return bytecode_estimate;
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "public interface $classname$OrBuilder extends \n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.GeneratedMessageLite.\n"
+ " ExtendableMessageOrBuilder<\n"
+ " $classname$, $classname$.Builder> {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name());
+ } else {
+ printer->Print(
+ "public interface $classname$OrBuilder extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.MessageLiteOrBuilder {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name());
+ }
+
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateInterfaceMembers(printer);
+ }
+ printer->Outdent();
+
+ printer->Print("}\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
+ bool is_own_file =
+ descriptor_->containing_type() == NULL &&
+ MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+
+ map<string, string> variables;
+ variables["static"] = is_own_file ? " " : " static ";
+ variables["classname"] = descriptor_->name();
+ variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+
+ 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) {
+ printer->Print(variables,
+ "public $static$final class $classname$ extends\n"
+ " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
+ " $classname$, $classname$.Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n");
+ builder_type = strings::Substitute(
+ "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>",
+ name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ printer->Print(variables,
+ "public $static$final class $classname$ extends\n"
+ " com.google.protobuf.GeneratedMessageLite<\n"
+ " $classname$, $classname$.Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n");
+
+ builder_type = "com.google.protobuf.GeneratedMessageLite.Builder";
+ }
+ printer->Indent();
+
+ GenerateParsingConstructor(printer);
+
+ // Nested types
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ EnumGenerator(descriptor_->enum_type(i), true, context_)
+ .Generate(printer);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // Don't generate Java classes for map entry messages.
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageLiteGenerator messageGenerator(
+ descriptor_->nested_type(i), context_);
+ messageGenerator.GenerateInterface(printer);
+ messageGenerator.Generate(printer);
+ }
+
+ if (GenerateHasBits(descriptor_)) {
+ // Integers for bit fields.
+ int totalBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ totalBits += field_generators_.get(descriptor_->field(i))
+ .GetNumBitsForMessage();
+ }
+ int totalInts = (totalBits + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ // oneof
+ map<string, string> vars;
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name;
+ vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name;
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ // oneofCase_ and oneof_
+ printer->Print(vars,
+ "private int $oneof_name$Case_ = 0;\n"
+ "private java.lang.Object $oneof_name$_;\n");
+ // OneofCase enum
+ printer->Print(vars,
+ "public enum $oneof_capitalized_name$Case\n"
+ " implements com.google.protobuf.Internal.EnumLite {\n");
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "$field_name$($field_number$),\n",
+ "field_name",
+ ToUpper(field->name()),
+ "field_number",
+ SimpleItoa(field->number()));
+ }
+ printer->Print(
+ "$cap_oneof_name$_NOT_SET(0);\n",
+ "cap_oneof_name",
+ ToUpper(vars["oneof_name"]));
+ printer->Print(vars,
+ "private int value = 0;\n"
+ "private $oneof_capitalized_name$Case(int value) {\n"
+ " this.value = value;\n"
+ "}\n");
+ printer->Print(vars,
+ "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+ " switch (value) {\n");
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ " case $field_number$: return $field_name$;\n",
+ "field_number",
+ SimpleItoa(field->number()),
+ "field_name",
+ ToUpper(field->name()));
+ }
+ printer->Print(
+ " case 0: return $cap_oneof_name$_NOT_SET;\n"
+ " default: throw new java.lang.IllegalArgumentException(\n"
+ " \"Value is undefined for this oneof enum.\");\n"
+ " }\n"
+ "}\n"
+ "public int getNumber() {\n"
+ " return this.value;\n"
+ "}\n",
+ "cap_oneof_name", ToUpper(vars["oneof_name"]));
+ printer->Outdent();
+ printer->Print("};\n\n");
+ // oneofCase()
+ printer->Print(vars,
+ "public $oneof_capitalized_name$Case\n"
+ "get$oneof_capitalized_name$Case() {\n"
+ " return $oneof_capitalized_name$Case.valueOf(\n"
+ " $oneof_name$Case_);\n"
+ "}\n"
+ "\n"
+ "private void clear$oneof_capitalized_name$() {\n"
+ " $oneof_name$Case_ = 0;\n"
+ " $oneof_name$_ = null;\n"
+ "}\n"
+ "\n");
+ }
+
+ // Fields
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("public static final int $constant_name$ = $number$;\n",
+ "constant_name", FieldConstantName(descriptor_->field(i)),
+ "number", SimpleItoa(descriptor_->field(i)->number()));
+ field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+ printer->Print("\n");
+ }
+
+ GenerateMessageSerializationMethods(printer);
+
+ if (HasEqualsAndHashCode(descriptor_)) {
+ GenerateEqualsAndHashCode(printer);
+ }
+
+
+ GenerateParseFromMethods(printer);
+ GenerateBuilder(printer);
+
+ if (HasRequiredFields(descriptor_)) {
+ // Memoizes whether the protocol buffer is fully initialized (has all
+ // required fields). -1 means not yet computed. 0 means false and 1 means
+ // true.
+ printer->Print(
+ "private byte memoizedIsInitialized = -1;\n");
+ }
+
+ printer->Print(
+ "protected final Object dynamicMethod(\n"
+ " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n"
+ " Object... args) {\n"
+ " switch (method) {\n"
+ " case PARSE_PARTIAL_FROM: {\n"
+ " return new $classname$("
+ " (com.google.protobuf.CodedInputStream) args[0],\n"
+ " (com.google.protobuf.ExtensionRegistryLite) args[1]);\n"
+ " }\n"
+ " case NEW_INSTANCE: {\n"
+ " return new $classname$(\n"
+ " com.google.protobuf.Internal.EMPTY_CODED_INPUT_STREAM,\n"
+ " com.google.protobuf.ExtensionRegistryLite\n"
+ " .getEmptyRegistry());\n"
+ " }\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Indent();
+ printer->Indent();
+
+ printer->Print(
+ "case IS_INITIALIZED: {\n");
+ printer->Indent();
+ GenerateDynamicMethodIsInitialized(printer);
+ printer->Outdent();
+
+ printer->Print(
+ "}\n"
+ "case MAKE_IMMUTABLE: {\n");
+
+ printer->Indent();
+ GenerateDynamicMethodMakeImmutable(printer);
+ printer->Outdent();
+
+ printer->Print(
+ "}\n"
+ "case NEW_BUILDER: {\n");
+
+ printer->Indent();
+ GenerateDynamicMethodNewBuilder(printer);
+ printer->Outdent();
+
+ printer->Print(
+ "}\n"
+ "case MERGE_FROM: {\n");
+
+ printer->Indent();
+ GenerateDynamicMethodMergeFrom(printer);
+ printer->Outdent();
+
+ printer->Print(
+ "}\n");
+
+ printer->Outdent();
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ " throw new UnsupportedOperationException();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
+
+ // Carefully initialize the default instance in such a way that it doesn't
+ // conflict with other initialization.
+ printer->Print(
+ "private static final $classname$ DEFAULT_INSTANCE;\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "static {\n"
+ " DEFAULT_INSTANCE = new $classname$(\n"
+ " com.google.protobuf.Internal\n"
+ " .EMPTY_CODED_INPUT_STREAM,\n"
+ " com.google.protobuf.ExtensionRegistryLite\n"
+ " .getEmptyRegistry());\n"
+ "}\n"
+ "\n",
+ "classname", descriptor_->name());
+ printer->Print(
+ "public static $classname$ getDefaultInstance() {\n"
+ " return DEFAULT_INSTANCE;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ GenerateParser(printer);
+
+ // LITE_RUNTIME uses this to implement the *ForType methods at the
+ // GeneratedMessageLite level.
+ printer->Print(
+ "static {\n"
+ " com.google.protobuf.GeneratedMessageLite.onLoad(\n"
+ " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n"
+ " .PrototypeHolder<$classname$, Builder>(\n"
+ " DEFAULT_INSTANCE, PARSER));"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+ // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
+ // the outer class's FileDescriptor.
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+ .Generate(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+ google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ vector<const Descriptor::ExtensionRange*> sorted_extensions;
+ for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+ sorted_extensions.push_back(descriptor_->extension_range(i));
+ }
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeOrdering());
+
+ printer->Print(
+ "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
+ " throws java.io.IOException {\n");
+ printer->Indent();
+ if (HasPackedFields(descriptor_)) {
+ // writeTo(CodedOutputStream output) might be invoked without
+ // getSerializedSize() ever being called, but we need the memoized
+ // sizes in case this message has packed fields. Rather than emit checks for
+ // each packed field, just call getSerializedSize() up front.
+ // In most cases, getSerializedSize() will have already been called anyway
+ // by one of the wrapper writeTo() methods, making this call cheap.
+ printer->Print(
+ "getSerializedSize();\n");
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ if (descriptor_->options().message_set_wire_format()) {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessageLite\n"
+ " .ExtendableMessage<$classname$, $classname$.Builder>\n"
+ " .ExtensionWriter extensionWriter =\n"
+ " newMessageSetExtensionWriter();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessageLite\n"
+ " .ExtendableMessage<$classname$, $classname$.Builder>\n"
+ " .ExtensionWriter extensionWriter =\n"
+ " newExtensionWriter();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ }
+ }
+
+ // Merge the fields and the extension ranges, both sorted by field number.
+ for (int i = 0, j = 0;
+ i < descriptor_->field_count() || j < sorted_extensions.size();
+ ) {
+ if (i == descriptor_->field_count()) {
+ GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+ } else if (j == sorted_extensions.size()) {
+ GenerateSerializeOneField(printer, sorted_fields[i++]);
+ } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) {
+ GenerateSerializeOneField(printer, sorted_fields[i++]);
+ } else {
+ GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+ }
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ "unknownFields.writeTo(output);\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n"
+ "public int getSerializedSize() {\n"
+ " int size = memoizedSerializedSize;\n"
+ " if (size != -1) return size;\n"
+ "\n"
+ " size = 0;\n");
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ if (descriptor_->options().message_set_wire_format()) {
+ printer->Print(
+ "size += extensionsSerializedSizeAsMessageSet();\n");
+ } else {
+ printer->Print(
+ "size += extensionsSerializedSize();\n");
+ }
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ "size += unknownFields.getSerializedSize();\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " memoizedSerializedSize = size;\n"
+ " return size;\n"
+ "}\n"
+ "\n");
+
+ printer->Print(
+ "private static final long serialVersionUID = 0L;\n");
+}
+
+void ImmutableMessageLiteGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+ printer->Print(
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.ByteString data)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\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 PARSER.parseFrom(data, extensionRegistry);\n"
+ "}\n"
+ "public static $classname$ parseFrom(byte[] data)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\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 PARSER.parseFrom(data, extensionRegistry);\n"
+ "}\n"
+ "public static $classname$ parseFrom(java.io.InputStream input)\n"
+ " throws java.io.IOException {\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 PARSER.parseFrom(input, extensionRegistry);\n"
+ "}\n"
+ "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
+ " throws java.io.IOException {\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"
+ " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.CodedInputStream input)\n"
+ " throws java.io.IOException {\n"
+ " return PARSER.parseFrom(input);\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+ " throws java.io.IOException {\n"
+ " return PARSER.parseFrom(input, extensionRegistry);\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+void ImmutableMessageLiteGenerator::GenerateSerializeOneField(
+ io::Printer* printer, const FieldDescriptor* field) {
+ field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void ImmutableMessageLiteGenerator::GenerateSerializeOneExtensionRange(
+ io::Printer* printer, const Descriptor::ExtensionRange* range) {
+ printer->Print(
+ "extensionWriter.writeUntil($end$, output);\n",
+ "end", SimpleItoa(range->end));
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateBuilder(io::Printer* printer) {
+ printer->Print(
+ "public static Builder newBuilder() {\n"
+ " return DEFAULT_INSTANCE.toBuilder();\n"
+ "}\n"
+ "public static Builder newBuilder($classname$ prototype) {\n"
+ " return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ MessageBuilderLiteGenerator builderGenerator(descriptor_, context_);
+ builderGenerator.Generate(printer);
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized(
+ io::Printer* printer) {
+ // Returns null for false, DEFAULT_INSTANCE for true.
+ if (!HasRequiredFields(descriptor_)) {
+ printer->Print("return DEFAULT_INSTANCE;\n");
+ return;
+ }
+
+ // Don't directly compare to -1 to avoid an Android x86 JIT bug.
+ printer->Print(
+ "byte isInitialized = memoizedIsInitialized;\n"
+ "if (isInitialized == 1) return DEFAULT_INSTANCE;\n"
+ "if (isInitialized == 0) return null;\n"
+ "\n"
+ "boolean shouldMemoize = ((Boolean) args[0]).booleanValue();\n");
+
+ // Check that all required fields in this message are set.
+ // TODO(kenton): We can optimize this when we switch to putting all the
+ // "has" fields into a single bitfield.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+
+ if (field->is_required()) {
+ printer->Print(
+ "if (!has$name$()) {\n"
+ " if (shouldMemoize) {\n"
+ " memoizedIsInitialized = 0;\n"
+ " }\n"
+ " return null;\n"
+ "}\n",
+ "name", info->capitalized_name);
+ }
+ }
+
+ // Now check that all embedded messages are initialized.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+ HasRequiredFields(field->message_type())) {
+ switch (field->label()) {
+ case FieldDescriptor::LABEL_REQUIRED:
+ printer->Print(
+ "if (!get$name$().isInitialized()) {\n"
+ " if (shouldMemoize) {\n"
+ " memoizedIsInitialized = 0;\n"
+ " }\n"
+ " return null;\n"
+ "}\n",
+ "type", name_resolver_->GetImmutableClassName(
+ field->message_type()),
+ "name", info->capitalized_name);
+ break;
+ case FieldDescriptor::LABEL_OPTIONAL:
+ if (!SupportFieldPresence(descriptor_->file()) &&
+ field->containing_oneof() != NULL) {
+ const OneofDescriptor* oneof = field->containing_oneof();
+ const OneofGeneratorInfo* oneof_info =
+ context_->GetOneofGeneratorInfo(oneof);
+ printer->Print(
+ "if ($oneof_name$Case_ == $field_number$) {\n",
+ "oneof_name", oneof_info->name,
+ "field_number", SimpleItoa(field->number()));
+ } else {
+ printer->Print(
+ "if (has$name$()) {\n",
+ "name", info->capitalized_name);
+ }
+ printer->Print(
+ " if (!get$name$().isInitialized()) {\n"
+ " if (shouldMemoize) {\n"
+ " memoizedIsInitialized = 0;\n"
+ " }\n"
+ " return null;\n"
+ " }\n"
+ "}\n",
+ "name", info->capitalized_name);
+ break;
+ case FieldDescriptor::LABEL_REPEATED:
+ if (IsMapEntry(field->message_type())) {
+ printer->Print(
+ "for ($type$ item : get$name$().values()) {\n"
+ " if (!item.isInitialized()) {\n"
+ " if (shouldMemoize) {\n"
+ " memoizedIsInitialized = 0;\n"
+ " }\n"
+ " return null;\n"
+ " }\n"
+ "}\n",
+ "type", MapValueImmutableClassdName(field->message_type(),
+ name_resolver_),
+ "name", info->capitalized_name);
+ } else {
+ printer->Print(
+ "for (int i = 0; i < get$name$Count(); i++) {\n"
+ " if (!get$name$(i).isInitialized()) {\n"
+ " if (shouldMemoize) {\n"
+ " memoizedIsInitialized = 0;\n"
+ " }\n"
+ " return null;\n"
+ " }\n"
+ "}\n",
+ "type", name_resolver_->GetImmutableClassName(
+ field->message_type()),
+ "name", info->capitalized_name);
+ }
+ break;
+ }
+ }
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "if (!extensionsAreInitialized()) {\n"
+ " if (shouldMemoize) {\n"
+ " memoizedIsInitialized = 0;\n"
+ " }\n"
+ " return null;\n"
+ "}\n");
+ }
+
+ printer->Print(
+ "if (shouldMemoize) memoizedIsInitialized = 1;\n");
+
+ printer->Print(
+ "return DEFAULT_INSTANCE;\n"
+ "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable(
+ io::Printer* printer) {
+ // Output generation code for each field.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateDynamicMethodMakeImmutableCode(printer);
+ }
+ printer->Print(
+ "return null;");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder(
+ io::Printer* printer) {
+ printer->Print(
+ "return new Builder();");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom(
+ io::Printer* printer) {
+ printer->Print(
+ // Optimization: If other is the default instance, we know none of its
+ // fields are set so we can skip the merge.
+ "Object arg = args[0];\n"
+ "if (arg == $classname$.getDefaultInstance()) return this;\n"
+ "$classname$ other = ($classname$) arg;\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(
+ descriptor_->field(i)).GenerateMergingCode(printer);
+ }
+ }
+
+ // Merge oneof fields.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+ printer->Print(
+ "switch (other.get$oneof_capitalized_name$Case()) {\n",
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name);
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "case $field_name$: {\n",
+ "field_name",
+ ToUpper(field->name()));
+ printer->Indent();
+ field_generators_.get(field).GenerateMergingCode(printer);
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ printer->Print(
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "cap_oneof_name",
+ ToUpper(context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name));
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+
+ // if message type has extensions
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "this.mergeExtensionFields(other);\n");
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ "this.mergeUnknownFields(other.unknownFields);\n");
+ }
+
+ printer->Print(
+ "return this;\n");
+}
+
+// ===================================================================
+
+namespace {
+bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) {
+ if (field->is_repeated()) {
+ return false;
+ }
+ if (SupportFieldPresence(field->file())) {
+ return true;
+ }
+ return GetJavaType(field) == JAVATYPE_MESSAGE &&
+ field->containing_oneof() == NULL;
+}
+} // namespace
+
+void ImmutableMessageLiteGenerator::
+GenerateEqualsAndHashCode(io::Printer* printer) {
+ printer->Print(
+ "@java.lang.Override\n"
+ "public boolean equals(final java.lang.Object obj) {\n");
+ printer->Indent();
+ printer->Print(
+ "if (obj == this) {\n"
+ " return true;\n"
+ "}\n"
+ "if (!(obj instanceof $classname$)) {\n"
+ " return super.equals(obj);\n"
+ "}\n"
+ "$classname$ other = ($classname$) obj;\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print("boolean result = true;\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
+ printer->Print(
+ "result = result && (has$name$() == other.has$name$());\n"
+ "if (has$name$()) {\n",
+ "name", info->capitalized_name);
+ printer->Indent();
+ }
+ field_generators_.get(field).GenerateEqualsCode(printer);
+ if (check_has_bits) {
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ }
+ if (PreserveUnknownFields(descriptor_)) {
+ // Always consider unknown fields for equality. This will sometimes return
+ // false for non-canonical ordering when running in LITE_RUNTIME but it's
+ // the best we can do.
+ printer->Print(
+ "result = result && unknownFields.equals(other.unknownFields);\n");
+ }
+ printer->Print(
+ "return result;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+
+ printer->Print(
+ "@java.lang.Override\n"
+ "public int hashCode() {\n");
+ printer->Indent();
+ printer->Print(
+ "if (memoizedHashCode != 0) {\n");
+ printer->Indent();
+ printer->Print(
+ "return memoizedHashCode;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "int hash = 41;\n");
+
+ // Include the hash of the class so that two objects with different types
+ // but the same field values will probably have different hashes.
+ printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
+ printer->Print(
+ "if (has$name$()) {\n",
+ "name", info->capitalized_name);
+ printer->Indent();
+ }
+ field_generators_.get(field).GenerateHashCode(printer);
+ if (check_has_bits) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+
+ printer->Print(
+ "hash = (29 * hash) + unknownFields.hashCode();\n");
+ printer->Print(
+ "memoizedHashCode = hash;\n"
+ "return hash;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateExtensionRegistrationCode(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+ .GenerateRegistrationCode(printer);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateExtensionRegistrationCode(printer);
+ }
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::
+GenerateParsingConstructor(io::Printer* printer) {
+ google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "private $classname$(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ // Initialize all fields to default.
+ GenerateInitializers(printer);
+
+ // Use builder bits to track mutable repeated fields.
+ int totalBuilderBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const ImmutableFieldLiteGenerator& field =
+ field_generators_.get(descriptor_->field(i));
+ totalBuilderBits += field.GetNumBitsForBuilder();
+ }
+ int totalBuilderInts = (totalBuilderBits + 31) / 32;
+ for (int i = 0; i < totalBuilderInts; i++) {
+ printer->Print("int mutable_$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ printer->Print(
+ "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
+ " com.google.protobuf.UnknownFieldSetLite.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");
+
+ if (PreserveUnknownFields(descriptor_)) {
+ if (descriptor_->extension_range_count() > 0) {
+ // Lite runtime directly invokes parseUnknownField to reduce method
+ // counts.
+ printer->Print(
+ "default: {\n"
+ " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
+ " input, unknownFields,\n"
+ " extensionRegistry, tag)) {\n"
+ " done = true;\n" // it's an endgroup tag
+ " }\n"
+ " break;\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "default: {\n"
+ " if (!parseUnknownField(input, unknownFields,\n"
+ " extensionRegistry, tag)) {\n"
+ " done = true;\n" // it's an endgroup tag
+ " }\n"
+ " break;\n"
+ "}\n");
+ }
+ } else {
+ printer->Print(
+ "default: {\n"
+ " if (!input.skipField(tag)) {\n"
+ " done = true;\n" // it's an endgroup tag
+ " }\n"
+ " break;\n"
+ "}\n");
+ }
+
+ 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 new RuntimeException(e.setUnfinishedMessage(this));\n"
+ "} catch (java.io.IOException e) {\n"
+ " throw new RuntimeException(\n"
+ " new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e.getMessage()).setUnfinishedMessage(this));\n"
+ "} 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);
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ // Make unknown fields immutable.
+ printer->Print("this.unknownFields = unknownFields.build();\n");
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ // Make extensions immutable.
+ printer->Print(
+ "makeExtensionsImmutable(extensions);\n");
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // finally
+ "}\n");
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) {
+ printer->Print(
+ "public static final com.google.protobuf.Parser<$classname$> PARSER =\n"
+ " new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n"
+ "\n",
+ "classname", descriptor_->name());
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateInitializationCode(printer);
+ }
+ }
+}
+
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
new file mode 100644
index 00000000..2bd3cdd4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -0,0 +1,91 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: dweis@google.com (Daniel Weis)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageLiteGenerator : public MessageGenerator {
+ public:
+ explicit ImmutableMessageLiteGenerator(const Descriptor* descriptor,
+ Context* context);
+ virtual ~ImmutableMessageLiteGenerator();
+
+ virtual void Generate(io::Printer* printer);
+ virtual void GenerateInterface(io::Printer* printer);
+ virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
+ virtual void GenerateStaticVariables(io::Printer* printer);
+ virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+
+ private:
+
+ void GenerateMessageSerializationMethods(io::Printer* printer);
+ void GenerateParseFromMethods(io::Printer* printer);
+ void GenerateSerializeOneField(io::Printer* printer,
+ const FieldDescriptor* field);
+ void GenerateSerializeOneExtensionRange(
+ io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+ void GenerateBuilder(io::Printer* printer);
+ void GenerateDynamicMethodIsInitialized(io::Printer* printer);
+ void GenerateDynamicMethodMakeImmutable(io::Printer* printer);
+ void GenerateDynamicMethodMergeFrom(io::Printer* printer);
+ void GenerateDynamicMethodNewBuilder(io::Printer* printer);
+ void GenerateInitializers(io::Printer* printer);
+ void GenerateEqualsAndHashCode(io::Printer* printer);
+ void GenerateParser(io::Printer* printer);
+ void GenerateParsingConstructor(io::Printer* printer);
+
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index e331d7a4..7bebe12a 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -74,7 +74,12 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
"" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
(*variables)["capitalized_type"] =
GetCapitalizedType(descriptor, /* immutable = */ true);
- (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+ if (descriptor->is_packed()) {
+ (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+ } else {
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+ }
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
if (IsReferenceType(GetJavaType(descriptor))) {
@@ -599,7 +604,7 @@ GenerateMembers(io::Printer* printer) const {
" return $name$_.get(index);\n"
"}\n");
- if (descriptor_->options().packed() &&
+ if (descriptor_->is_packed() &&
HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize = -1;\n");
@@ -771,7 +776,10 @@ GenerateParsingDoneCode(io::Printer* printer) const {
void RepeatedImmutablePrimitiveFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
+ // We invoke getSerializedSize in writeTo for messages that have packed
+ // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+ // That makes it safe to rely on the memoized size here.
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
" output.writeRawVarint32($tag$);\n"
@@ -809,7 +817,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(
"size += dataSize;\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (!get$capitalized_name$List().isEmpty()) {\n"
" size += $tag_size$;\n"
@@ -822,7 +830,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
// cache the data size for packed fields.
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"$name$MemoizedSerializedSize = dataSize;\n");
}
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
new file mode 100644
index 00000000..217ff9b6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -0,0 +1,892 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
+ map<string, string>* variables) {
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+ (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+ (*variables)["field_type"] = (*variables)["type"];
+ (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+ (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
+ "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
+ (*variables)["capitalized_type"] =
+ GetCapitalizedType(descriptor, /* immutable = */ true);
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+
+ string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(
+ GetJavaType(descriptor)), true /* cap_next_letter */);
+ switch (GetJavaType(descriptor)) {
+ case JAVATYPE_INT:
+ case JAVATYPE_LONG:
+ case JAVATYPE_FLOAT:
+ case JAVATYPE_DOUBLE:
+ case JAVATYPE_BOOLEAN:
+ (*variables)["field_list_type"] =
+ "com.google.protobuf.Internal." + capitalized_type + "List";
+ (*variables)["new_list"] = "new" + capitalized_type + "List";
+ (*variables)["empty_list"] = "empty" + capitalized_type + "List()";
+ (*variables)["make_name_unmodifiable"] =
+ (*variables)["name"] + "_.makeImmutable()";
+ (*variables)["repeated_index_get"] =
+ (*variables)["name"] + "_.get" + capitalized_type + "(index)";
+ (*variables)["repeated_add"] =
+ (*variables)["name"] + "_.add" + capitalized_type;
+ (*variables)["repeated_set"] =
+ (*variables)["name"] + "_.set" + capitalized_type;
+ break;
+ default:
+ (*variables)["field_list_type"] =
+ "com.google.protobuf.Internal.ProtobufList<" +
+ (*variables)["boxed_type"] + ">";
+ (*variables)["new_list"] = "newProtobufList";
+ (*variables)["empty_list"] = "emptyProtobufList()";
+ (*variables)["make_name_unmodifiable"] =
+ (*variables)["name"] + "_.makeImmutable()";
+ (*variables)["repeated_index_get"] =
+ (*variables)["name"] + "_.get(index)";
+ (*variables)["repeated_add"] = (*variables)["name"] + "_.add";
+ (*variables)["repeated_set"] = (*variables)["name"] + "_.set";
+ }
+
+ if (IsReferenceType(GetJavaType(descriptor))) {
+ (*variables)["null_check"] =
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n";
+ } else {
+ (*variables)["null_check"] = "";
+ }
+ // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+ // by the proto compiler
+ (*variables)["deprecation"] = descriptor->options().deprecated()
+ ? "@java.lang.Deprecated " : "";
+ int fixed_size = FixedSize(GetType(descriptor));
+ if (fixed_size != -1) {
+ (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+ }
+ (*variables)["on_changed"] =
+ HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["clear_has_field_bit_message"] =
+ GenerateClearBit(messageBitIndex) + ";";
+
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["clear_has_field_bit_message"] = "";
+
+ if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+ (*variables)["is_field_present_message"] =
+ "!" + (*variables)["name"] + "_.isEmpty()";
+ } else {
+ (*variables)["is_field_present_message"] =
+ (*variables)["name"] + "_ != " + (*variables)["default"];
+ }
+ }
+
+ // For repeated builders, the underlying list tracks mutability state.
+ (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+ (*variables)["get_has_field_bit_from_local"] =
+ GenerateGetBitFromLocal(builderBitIndex);
+ (*variables)["set_has_field_bit_to_local"] =
+ GenerateSetBitToLocal(messageBitIndex);
+}
+
+} // namespace
+
+// ===================================================================
+
+ImmutablePrimitiveFieldLiteGenerator::
+ImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 1;
+}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private $field_type$ $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ 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"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ "$null_check$"
+ " $set_has_field_bit_message$\n"
+ " $name$_ = value;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $clear_has_field_bit_message$\n");
+ JavaType type = GetJavaType(descriptor_);
+ if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
+ // The default value is not a simple literal so we want to avoid executing
+ // it multiple times. Instead, get the default out of the default instance.
+ printer->Print(variables_,
+ " $name$_ = getDefaultInstance().get$capitalized_name$();\n");
+ } else {
+ printer->Print(variables_,
+ " $name$_ = $default$;\n");
+ }
+ printer->Print(variables_,
+ "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (other.get$capitalized_name$() != $default$) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+ }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ // noop for scalars
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$set_has_field_bit_message$\n"
+ "$name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for primitives.
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " output.write$capitalized_type$($number$, $name$_);\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$Size($number$, $name$_);\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ switch (GetJavaType(descriptor_)) {
+ case JAVATYPE_INT:
+ case JAVATYPE_LONG:
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "result = result && (get$capitalized_name$()\n"
+ " == other.get$capitalized_name$());\n");
+ break;
+
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "result = result && (\n"
+ " java.lang.Float.floatToIntBits(get$capitalized_name$())\n"
+ " == java.lang.Float.floatToIntBits(\n"
+ " other.get$capitalized_name$()));\n");
+ break;
+
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "result = result && (\n"
+ " java.lang.Double.doubleToLongBits(get$capitalized_name$())\n"
+ " == java.lang.Double.doubleToLongBits(\n"
+ " other.get$capitalized_name$()));\n");
+ break;
+
+ case JAVATYPE_STRING:
+ case JAVATYPE_BYTES:
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$()\n"
+ " .equals(other.get$capitalized_name$());\n");
+ break;
+
+ case JAVATYPE_ENUM:
+ case JAVATYPE_MESSAGE:
+ default:
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ break;
+ }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "hash = (37 * hash) + $constant_name$;\n");
+ switch (GetJavaType(descriptor_)) {
+ case JAVATYPE_INT:
+ printer->Print(variables_,
+ "hash = (53 * hash) + get$capitalized_name$();\n");
+ break;
+
+ case JAVATYPE_LONG:
+ printer->Print(variables_,
+ "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+ " get$capitalized_name$());\n");
+ break;
+
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n"
+ " get$capitalized_name$());\n");
+ break;
+
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n"
+ " get$capitalized_name$());\n");
+ break;
+
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+ " java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n");
+ break;
+
+ case JAVATYPE_STRING:
+ case JAVATYPE_BYTES:
+ printer->Print(variables_,
+ "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+ break;
+
+ case JAVATYPE_ENUM:
+ case JAVATYPE_MESSAGE:
+ default:
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ break;
+ }
+}
+
+string ImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+ return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutablePrimitiveFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+~ImmutablePrimitiveOneofFieldLiteGenerator() {}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($boxed_type$) $oneof_name$_;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$($type$ value) {\n"
+ "$null_check$"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ "}\n");
+}
+
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "set$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.write$capitalized_type$(\n"
+ " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$Size(\n"
+ " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+ "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+RepeatedImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+~RepeatedImmutablePrimitiveFieldLiteGenerator() {}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 0;
+}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+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$$type$ get$capitalized_name$(int index);\n");
+}
+
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private $field_list_type$ $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ 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");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return $name$_.size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return $repeated_index_get$;\n"
+ "}\n");
+
+ if (descriptor_->options().packed() &&
+ HasGeneratedMethods(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ "private int $name$MemoizedSerializedSize = -1;\n");
+ }
+
+ printer->Print(variables_,
+ "private void ensure$capitalized_name$IsMutable() {\n"
+ " if (!$is_mutable$) {\n"
+ " $name$_ = $new_list$($name$_);\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ "$null_check$"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $repeated_set$(index, value);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$($type$ value) {\n"
+ "$null_check$"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $repeated_add$(value);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $boxed_type$> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " com.google.protobuf.AbstractMessageLite.addAll(\n"
+ " values, $name$_);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $name$_ = $empty_list$;\n"
+ "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$boxed_type$>\n"
+ " get$capitalized_name$List() {\n"
+ " return java.util.Collections.unmodifiableList(\n"
+ " instance.get$capitalized_name$List());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return instance.get$capitalized_name$Count();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return instance.get$capitalized_name$(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $boxed_type$> values) {\n"
+ " copyOnWrite();\n"
+ " instance.addAll$capitalized_name$(values);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // The code below does two optimizations:
+ // 1. If the other list is empty, there's nothing to do. This ensures we
+ // don't allocate a new array if we already have an immutable one.
+ // 2. If the other list is non-empty and our current list is empty, we can
+ // reuse the other list which is guaranteed to be immutable.
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if ($name$_.isEmpty()) {\n"
+ " $name$_ = other.$name$_;\n"
+ " } else {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.addAll(other.$name$_);\n"
+ " }\n"
+ " $on_changed$\n"
+ "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!$is_mutable$) {\n"
+ " $name$_ = $new_list$();\n"
+ "}\n"
+ "$repeated_add$(input.read$capitalized_type$());\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int length = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(length);\n"
+ "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
+ " $name$_ = $new_list$();\n"
+ "}\n"
+ "while (input.getBytesUntilLimit() > 0) {\n"
+ " $repeated_add$(input.read$capitalized_type$());\n"
+ "}\n"
+ "input.popLimit(limit);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_mutable$) {\n"
+ " $make_name_unmodifiable$;\n"
+ "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->options().packed()) {
+ // We invoke getSerializedSize in writeTo for messages that have packed
+ // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+ // That makes it safe to rely on the memoized size here.
+ printer->Print(variables_,
+ "if (get$capitalized_name$List().size() > 0) {\n"
+ " output.writeRawVarint32($tag$);\n"
+ " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ "}\n"
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.write$capitalized_type$NoTag($name$_.get(i));\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.write$capitalized_type$($number$, $name$_.get(i));\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " int dataSize = 0;\n");
+ printer->Indent();
+
+ if (FixedSize(GetType(descriptor_)) == -1) {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " dataSize += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$SizeNoTag($name$_.get(i));\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
+ }
+
+ printer->Print(
+ "size += dataSize;\n");
+
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (!get$capitalized_name$List().isEmpty()) {\n"
+ " size += $tag_size$;\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeInt32SizeNoTag(dataSize);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * get$capitalized_name$List().size();\n");
+ }
+
+ // cache the data size for packed fields.
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "$name$MemoizedSerializedSize = dataSize;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$List()\n"
+ " .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (get$capitalized_name$Count() > 0) {\n"
+ " hash = (37 * hash) + $constant_name$;\n"
+ " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+ "}\n");
+}
+
+string RepeatedImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+ return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
new file mode 100644
index 00000000..ad603c2a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
@@ -0,0 +1,163 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutablePrimitiveFieldLiteGenerator
+ : public ImmutableFieldLiteGenerator {
+ public:
+ explicit ImmutablePrimitiveFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutablePrimitiveFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateBuilderClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(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;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ protected:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldLiteGenerator);
+};
+
+class ImmutablePrimitiveOneofFieldLiteGenerator
+ : public ImmutablePrimitiveFieldLiteGenerator {
+ public:
+ ImmutablePrimitiveOneofFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutablePrimitiveOneofFieldLiteGenerator();
+
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutablePrimitiveFieldLiteGenerator
+ : public ImmutableFieldLiteGenerator {
+ public:
+ explicit RepeatedImmutablePrimitiveFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ virtual ~RepeatedImmutablePrimitiveFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateBuilderClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index 2e61ea8a..70177367 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -171,7 +171,7 @@ void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) {
string classname = FileJavaPackage(file_->dependency(i)) + "." +
name_resolver_->GetDescriptorClassName(
file_->dependency(i));
- dependencies.push_back(make_pair(filename, classname));
+ dependencies.push_back(std::make_pair(filename, classname));
}
}
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 1c9302af..68e863cc 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -208,7 +208,7 @@ GenerateInterfaceMembers(io::Printer* printer) const {
void ImmutableStringFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.lang.Object $name$_;\n");
+ "private volatile java.lang.Object $name$_;\n");
PrintExtraFieldInfo(variables_, printer);
if (SupportFieldPresence(descriptor_->file())) {
@@ -667,7 +667,7 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
"String s = input.readStringRequireUtf8();\n"
"$set_oneof_case_message$;\n"
- "$oneof_name$_ = s;\n}\n");
+ "$oneof_name$_ = s;\n");
} else if (!HasDescriptorMethods(descriptor_->file())) {
// Lite runtime should attempt to reduce allocations by attempting to
// construct the string directly from the input stream buffer. This avoids
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
new file mode 100644
index 00000000..51bb245c
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -0,0 +1,1013 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Author: jonp@google.com (Jon Perlow)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_string_field_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
+ map<string, string>* variables) {
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["empty_list"] = "emptyLazyStringArrayList()";
+
+ (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+ (*variables)["default_init"] =
+ "= " + ImmutableDefaultValue(descriptor, name_resolver);
+ (*variables)["capitalized_type"] = "String";
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+ (*variables)["null_check"] =
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n";
+
+ // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+ // by the proto compiler
+ (*variables)["deprecation"] = descriptor->options().deprecated()
+ ? "@java.lang.Deprecated " : "";
+ (*variables)["on_changed"] =
+ HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["clear_has_field_bit_message"] =
+ GenerateClearBit(messageBitIndex) + ";";
+
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["clear_has_field_bit_message"] = "";
+
+ (*variables)["is_field_present_message"] =
+ "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()";
+ }
+
+ // For repeated builders, the underlying list tracks mutability state.
+ (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+ (*variables)["get_has_field_bit_from_local"] =
+ GenerateGetBitFromLocal(builderBitIndex);
+ (*variables)["set_has_field_bit_to_local"] =
+ GenerateSetBitToLocal(messageBitIndex);
+}
+
+bool CheckUtf8(const FieldDescriptor* descriptor) {
+ return descriptor->file()->options().java_string_check_utf8();
+}
+
+} // namespace
+
+// ===================================================================
+
+ImmutableStringFieldLiteGenerator::
+ImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 1;
+}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+// A note about how strings are handled. This code used to just store a String
+// in the Message. This had two issues:
+//
+// 1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded
+// strings, but rather fields that were raw bytes incorrectly marked
+// as strings in the proto file. This is common because in the proto1
+// syntax, string was the way to indicate bytes and C++ engineers can
+// easily make this mistake without affecting the C++ API. By converting to
+// strings immediately, some java code might corrupt these byte arrays as
+// it passes through a java server even if the field was never accessed by
+// application code.
+//
+// 2. There's a performance hit to converting between bytes and strings and
+// it many cases, the field is never even read by the application code. This
+// avoids unnecessary conversions in the common use cases.
+//
+// So now, the field for String is maintained as an Object reference which can
+// either store a String or a ByteString. The code uses an instanceof check
+// to see which one it has and converts to the other one if needed. It remembers
+// the last value requested (in a thread safe manner) as this is most likely
+// the one needed next. The thread safety is such that if two threads both
+// convert the field because the changes made by each thread were not visible to
+// the other, they may cause a conversion to happen more times than would
+// otherwise be necessary. This was deemed better than adding synchronization
+// overhead. It will not cause any corruption issues or affect the behavior of
+// the API. The instanceof check is also highly optimized in the JVM and we
+// decided it was better to reduce the memory overhead by not having two
+// separate fields but rather use dynamic type checking.
+//
+// For single fields, the logic for this is done inside the generated code. For
+// repeated fields, the logic is done in LazyStringArrayList and
+// UnmodifiableLazyStringList.
+void ImmutableStringFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$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 ImmutableStringFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private java.lang.Object $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ 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"
+ " if (ref instanceof java.lang.String) {\n"
+ " return (java.lang.String) ref;\n"
+ " } else {\n"
+ " com.google.protobuf.ByteString bs = \n"
+ " (com.google.protobuf.ByteString) ref;\n"
+ " java.lang.String s = bs.toStringUtf8();\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " $name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ " if (bs.isValidUtf8()) {\n"
+ " $name$_ = s;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " return s;\n"
+ " }\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"
+ " 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_,
+ "private void set$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ "$null_check$"
+ " $set_has_field_bit_message$\n"
+ " $name$_ = value;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $clear_has_field_bit_message$\n"
+ // The default value is not a simple literal so we want to avoid executing
+ // it multiple times. Instead, get the default out of the default instance.
+ " $name$_ = getDefaultInstance().get$capitalized_name$();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " checkByteStringIsUtf8(value);\n");
+ }
+ printer->Print(variables_,
+ " $set_has_field_bit_message$\n"
+ " $name$_ = value;\n"
+ "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " return instance.get$capitalized_name$Bytes();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$Bytes(value);\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // noop for strings
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ // Allow a slight breach of abstraction here in order to avoid forcing
+ // all string fields to Strings when copying fields from a Message.
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " $set_has_field_bit_message$\n"
+ " $name$_ = other.$name$_;\n"
+ " $on_changed$\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (!other.get$capitalized_name$().isEmpty()) {\n"
+ " $name$_ = other.$name$_;\n"
+ " $on_changed$\n"
+ "}\n");
+ }
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ // noop for scalars
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ "String s = input.readStringRequireUtf8();\n"
+ "$set_has_field_bit_message$\n"
+ "$name$_ = s;\n");
+ } else if (!HasDescriptorMethods(descriptor_->file())) {
+ // Lite runtime should attempt to reduce allocations by attempting to
+ // construct the string directly from the input stream buffer. This avoids
+ // spurious intermediary ByteString allocations, cutting overall allocations
+ // in half.
+ printer->Print(variables_,
+ "String s = input.readString();\n"
+ "$set_has_field_bit_message$\n"
+ "$name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ "com.google.protobuf.ByteString bs = input.readBytes();\n"
+ "$set_has_field_bit_message$\n"
+ "$name$_ = bs;\n");
+ }
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for strings
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+ "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_field_present_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+ "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$()\n"
+ " .equals(other.get$capitalized_name$());\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "hash = (37 * hash) + $constant_name$;\n");
+ printer->Print(variables_,
+ "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+string ImmutableStringFieldLiteGenerator::GetBoxedType() const {
+ return "java.lang.String";
+}
+
+// ===================================================================
+
+ImmutableStringOneofFieldLiteGenerator::
+ImmutableStringOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableStringFieldLiteGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableStringOneofFieldLiteGenerator::
+~ImmutableStringOneofFieldLiteGenerator() {}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+ " java.lang.Object ref $default_init$;\n"
+ " if ($has_oneof_case_message$) {\n"
+ " ref = $oneof_name$_;\n"
+ " }\n"
+ " if (ref instanceof java.lang.String) {\n"
+ " return (java.lang.String) ref;\n"
+ " } else {\n"
+ " com.google.protobuf.ByteString bs = \n"
+ " (com.google.protobuf.ByteString) ref;\n"
+ " java.lang.String s = bs.toStringUtf8();\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " if ($has_oneof_case_message$) {\n"
+ " $oneof_name$_ = s;\n"
+ " }\n");
+ } else {
+ printer->Print(variables_,
+ " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = s;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " return s;\n"
+ " }\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " java.lang.Object ref $default_init$;\n"
+ " if ($has_oneof_case_message$) {\n"
+ " ref = $oneof_name$_;\n"
+ " }\n"
+ " if (ref instanceof java.lang.String) {\n"
+ " com.google.protobuf.ByteString b = \n"
+ " com.google.protobuf.ByteString.copyFromUtf8(\n"
+ " (java.lang.String) ref);\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $oneof_name$_ = b;\n"
+ " }\n"
+ " return b;\n"
+ " } else {\n"
+ " return (com.google.protobuf.ByteString) ref;\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ "$null_check$"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " checkByteStringIsUtf8(value);\n");
+ }
+ printer->Print(variables_,
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return instance.has$capitalized_name$();\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+ " return instance.get$capitalized_name$();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " return instance.get$capitalized_name$Bytes();\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$Bytes(value);\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // Allow a slight breach of abstraction here in order to avoid forcing
+ // all string fields to Strings when copying fields from a Message.
+ printer->Print(variables_,
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = other.$oneof_name$_;\n"
+ "$on_changed$\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ "String s = input.readStringRequireUtf8();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = s;\n");
+ } else if (!HasDescriptorMethods(descriptor_->file())) {
+ // Lite runtime should attempt to reduce allocations by attempting to
+ // construct the string directly from the input stream buffer. This avoids
+ // spurious intermediary ByteString allocations, cutting overall allocations
+ // in half.
+ printer->Print(variables_,
+ "String s = input.readString();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ "com.google.protobuf.ByteString bs = input.readBytes();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = bs;\n");
+ }
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+ "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+ "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableStringFieldLiteGenerator::
+RepeatedImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+RepeatedImmutableStringFieldLiteGenerator::
+~RepeatedImmutableStringFieldLiteGenerator() {}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+ return 0;
+}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const {
+ return 0;
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$com.google.protobuf.ProtocolStringList\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 RepeatedImmutableStringFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private com.google.protobuf.LazyStringArrayList $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ProtocolStringList\n"
+ " get$capitalized_name$List() {\n"
+ " return $name$_;\n" // note: unmodifiable list
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return $name$_.size();\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())) {
+ printer->Print(variables_,
+ "private int $name$MemoizedSerializedSize = -1;\n");
+ }
+
+ printer->Print(variables_,
+ "private void ensure$capitalized_name$IsMutable() {\n"
+ " if (!$is_mutable$) {\n"
+ " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void set$capitalized_name$(\n"
+ " int index, java.lang.String value) {\n"
+ "$null_check$"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, value);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ "$null_check$"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(value);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void addAll$capitalized_name$(\n"
+ " java.lang.Iterable<java.lang.String> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " com.google.protobuf.AbstractMessageLite.addAll(\n"
+ " values, $name$_);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void clear$capitalized_name$() {\n"
+ " $name$_ = $empty_list$;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private void add$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " checkByteStringIsUtf8(value);\n");
+ }
+ printer->Print(variables_,
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(value);\n"
+ "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ProtocolStringList\n"
+ " get$capitalized_name$List() {\n"
+ " return ((com.google.protobuf.LazyStringList)\n"
+ " instance.get$capitalized_name$List()).getUnmodifiableView();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return instance.get$capitalized_name$Count();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
+ " return instance.get$capitalized_name$(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index) {\n"
+ " return instance.get$capitalized_name$Bytes(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, java.lang.String value) {\n"
+ " copyOnWrite();\n"
+ " instance.set$capitalized_name$(index, value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$(value);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<java.lang.String> values) {\n"
+ " copyOnWrite();\n"
+ " instance.addAll$capitalized_name$(values);\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.clear$capitalized_name$();\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ " copyOnWrite();\n"
+ " instance.add$capitalized_name$Bytes(value);\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+ // noop for strings
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // The code below does two optimizations:
+ // 1. If the other list is empty, there's nothing to do. This ensures we
+ // don't allocate a new array if we already have an immutable one.
+ // 2. If the other list is non-empty and our current list is empty, we can
+ // reuse the other list which is guaranteed to be immutable.
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if ($name$_.isEmpty()) {\n"
+ " $name$_ = other.$name$_;\n"
+ " } else {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.addAll(other.$name$_);\n"
+ " }\n"
+ " $on_changed$\n"
+ "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ "String s = input.readStringRequireUtf8();\n");
+ } else if (!HasDescriptorMethods(descriptor_->file())) {
+ // Lite runtime should attempt to reduce allocations by attempting to
+ // construct the string directly from the input stream buffer. This avoids
+ // spurious intermediary ByteString allocations, cutting overall allocations
+ // in half.
+ printer->Print(variables_,
+ "String s = input.readString();\n");
+ } else {
+ printer->Print(variables_,
+ "com.google.protobuf.ByteString bs = input.readBytes();\n");
+ }
+ printer->Print(variables_,
+ "if (!$is_mutable$) {\n"
+ " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+ "}\n");
+ if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(variables_,
+ "$name$_.add(s);\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_.add(bs);\n");
+ }
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int length = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(length);\n"
+ "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
+ " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+ "}\n"
+ "while (input.getBytesUntilLimit() > 0) {\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " String s = input.readStringRequireUtf8();\n");
+ } else {
+ printer->Print(variables_,
+ " String s = input.readString();\n");
+ }
+ printer->Print(variables_,
+ " $name$.add(s);\n");
+ printer->Print(variables_,
+ "}\n"
+ "input.popLimit(limit);\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($is_mutable$) {\n"
+ " $name$_.makeImmutable();\n"
+ "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (get$capitalized_name$List().size() > 0) {\n"
+ " output.writeRawVarint32($tag$);\n"
+ " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ "}\n"
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.write$capitalized_type$NoTag($name$_.get(i));\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.writeBytes($number$, $name$_.getByteString(i));\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " int dataSize = 0;\n");
+ printer->Indent();
+
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " dataSize += com.google.protobuf.CodedOutputStream\n"
+ " .computeBytesSizeNoTag($name$_.getByteString(i));\n"
+ "}\n");
+
+ printer->Print(
+ "size += dataSize;\n");
+
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (!get$capitalized_name$List().isEmpty()) {\n"
+ " size += $tag_size$;\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeInt32SizeNoTag(dataSize);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * get$capitalized_name$List().size();\n");
+ }
+
+ // cache the data size for packed fields.
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "$name$MemoizedSerializedSize = dataSize;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = result && get$capitalized_name$List()\n"
+ " .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (get$capitalized_name$Count() > 0) {\n"
+ " hash = (37 * hash) + $constant_name$;\n"
+ " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+ "}\n");
+}
+
+string RepeatedImmutableStringFieldLiteGenerator::GetBoxedType() const {
+ return "String";
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
new file mode 100644
index 00000000..9d93b307
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -0,0 +1,158 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Author: jonp@google.com (Jon Perlow)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+ explicit ImmutableStringFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableStringFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(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;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ protected:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldLiteGenerator);
+};
+
+class ImmutableStringOneofFieldLiteGenerator
+ : public ImmutableStringFieldLiteGenerator {
+ public:
+ ImmutableStringOneofFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableStringOneofFieldLiteGenerator();
+
+ private:
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableStringFieldLiteGenerator
+ : public ImmutableFieldLiteGenerator {
+ public:
+ explicit RepeatedImmutableStringFieldLiteGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableStringFieldLiteGenerator();
+
+ // implements ImmutableFieldLiteGenerator ------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc
index f934b05f..c6e8dfe9 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc
@@ -73,13 +73,45 @@ void EnumGenerator::Generate(io::Printer* printer) {
"// enum $classname$\n",
"classname", descriptor_->name());
+ const string classname = RenameJavaKeywords(descriptor_->name());
+
// Start of container interface
+ // If generating intdefs, we use the container interface as the intdef if
+ // present. Otherwise, we just make an empty @interface parallel to the
+ // constants.
+ bool use_intdef = params_.generate_intdefs();
bool use_shell_class = params_.java_enum_style();
- if (use_shell_class) {
- printer->Print(
- "public interface $classname$ {\n",
- "classname", RenameJavaKeywords(descriptor_->name()));
+ if (use_intdef) {
+ // @IntDef annotation so tools can enforce correctness
+ // Annotations will be discarded by the compiler
+ printer->Print("@java.lang.annotation.Retention("
+ "java.lang.annotation.RetentionPolicy.SOURCE)\n"
+ "@android.support.annotation.IntDef({\n");
printer->Indent();
+ for (int i = 0; i < canonical_values_.size(); i++) {
+ const string constant_name =
+ RenameJavaKeywords(canonical_values_[i]->name());
+ if (use_shell_class) {
+ printer->Print("$classname$.$name$,\n",
+ "classname", classname,
+ "name", constant_name);
+ } else {
+ printer->Print("$name$,\n", "name", constant_name);
+ }
+ }
+ printer->Outdent();
+ printer->Print("})\n");
+ }
+ if (use_shell_class || use_intdef) {
+ printer->Print(
+ "public $at_for_intdef$interface $classname$ {\n",
+ "classname", classname,
+ "at_for_intdef", use_intdef ? "@" : "");
+ if (use_shell_class) {
+ printer->Indent();
+ } else {
+ printer->Print("}\n\n");
+ }
}
// Canonical values
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
index 8a59d323..7666db38 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -76,6 +76,10 @@ void SetEnumVariables(const Params& params,
internal::WireFormatLite::MakeTag(descriptor->number(),
internal::WireFormat::WireTypeForFieldType(descriptor->type())));
(*variables)["message_name"] = descriptor->containing_type()->name();
+ const EnumDescriptor* enum_type = descriptor->enum_type();
+ (*variables)["message_type_intdef"] = "@"
+ + ToJavaName(params, enum_type->name(), true,
+ enum_type->containing_type(), enum_type->file());
}
void LoadEnumValues(const Params& params,
@@ -116,8 +120,10 @@ EnumFieldGenerator::~EnumFieldGenerator() {}
void EnumFieldGenerator::
GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
- printer->Print(variables_,
- "public $type$ $name$;\n");
+ if (params_.generate_intdefs()) {
+ printer->Print(variables_, "$message_type_intdef$\n");
+ }
+ printer->Print(variables_, "public $type$ $name$;\n");
if (params_.generate_has()) {
printer->Print(variables_,
@@ -256,12 +262,22 @@ AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
void AccessorEnumFieldGenerator::
GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_, "private int $name$_;\n");
+ if (params_.generate_intdefs()) {
+ printer->Print(variables_, "$message_type_intdef$\n");
+ }
printer->Print(variables_,
- "private int $name$_;\n"
"public int get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n"
- "public $message_name$ set$capitalized_name$(int value) {\n"
+ "public $message_name$ set$capitalized_name$(");
+ if (params_.generate_intdefs()) {
+ printer->Print(variables_,
+ "\n"
+ " $message_type_intdef$ ");
+ }
+ printer->Print(variables_,
+ "int value) {\n"
" $name$_ = value;\n"
" $set_has$;\n"
" return this;\n"
@@ -499,6 +515,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void RepeatedEnumFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " cloned.$name$ = this.$name$.clone();\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
index 00adc61f..b94790d6 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -106,6 +106,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc
index 754ed550..0b9d1d8d 100644
--- a/src/google/protobuf/compiler/javanano/javanano_extension.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -140,7 +140,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) const {
" com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n"
" com.google.protobuf.nano.Extension.$type$,\n"
" $class$.class,\n"
- " $tag_params$);\n");
+ " $tag_params$L);\n");
}
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.cc b/src/google/protobuf/compiler/javanano/javanano_field.cc
index e3e4cefe..85257f3f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_field.cc
@@ -36,6 +36,7 @@
#include <google/protobuf/compiler/javanano/javanano_helpers.h>
#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
+#include <google/protobuf/compiler/javanano/javanano_map_field.h>
#include <google/protobuf/compiler/javanano/javanano_message_field.h>
#include <google/protobuf/stubs/common.h>
@@ -97,12 +98,24 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
if (field->is_repeated()) {
switch (java_type) {
case JAVATYPE_MESSAGE:
- return new RepeatedMessageFieldGenerator(field, params);
+ if (IsMapEntry(field->message_type())) {
+ return new MapFieldGenerator(field, params);
+ } else {
+ return new RepeatedMessageFieldGenerator(field, params);
+ }
case JAVATYPE_ENUM:
return new RepeatedEnumFieldGenerator(field, params);
default:
return new RepeatedPrimitiveFieldGenerator(field, params);
}
+ } else if (field->containing_oneof()) {
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ return new MessageOneofFieldGenerator(field, params);
+ case JAVATYPE_ENUM:
+ default:
+ return new PrimitiveOneofFieldGenerator(field, params);
+ }
} else if (params.optional_field_accessors() && field->is_optional()
&& java_type != JAVATYPE_MESSAGE) {
// We need a has-bit for each primitive/enum field because their default
@@ -137,6 +150,59 @@ const FieldGenerator& FieldGeneratorMap::get(
return *field_generators_[field->index()];
}
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["oneof_name"] =
+ UnderscoresToCamelCase(descriptor->containing_oneof());
+ (*variables)["oneof_capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(descriptor->containing_oneof());
+ (*variables)["oneof_index"] =
+ SimpleItoa(descriptor->containing_oneof()->index());
+ (*variables)["set_oneof_case"] =
+ "this." + (*variables)["oneof_name"] +
+ "Case_ = " + SimpleItoa(descriptor->number());
+ (*variables)["clear_oneof_case"] =
+ "this." + (*variables)["oneof_name"] + "Case_ = 0";
+ (*variables)["has_oneof_case"] =
+ "this." + (*variables)["oneof_name"] + "Case_ == " +
+ SimpleItoa(descriptor->number());
+}
+
+void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer) {
+ if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
+ printer->Print(variables,
+ "if (this.has$capitalized_name$()) {\n"
+ " if (!java.util.Arrays.equals((byte[]) this.$oneof_name$_,\n"
+ " (byte[]) other.$oneof_name$_)) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ } else {
+ printer->Print(variables,
+ "if (this.has$capitalized_name$()) {\n"
+ " if (!this.$oneof_name$_.equals(other.$oneof_name$_)) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ }
+}
+
+void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer) {
+ if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
+ printer->Print(variables,
+ "result = 31 * result + ($has_oneof_case$\n"
+ " ? java.util.Arrays.hashCode((byte[]) this.$oneof_name$_) : 0);\n");
+ } else {
+ printer->Print(variables,
+ "result = 31 * result +\n"
+ " ($has_oneof_case$ ? this.$oneof_name$_.hashCode() : 0);\n");
+ }
+}
+
} // namespace javanano
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
index 6170c2c0..57c221f4 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -35,6 +35,7 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
+#include <map>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
@@ -82,6 +83,7 @@ class FieldGenerator {
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
virtual void GenerateHashCodeCode(io::Printer* printer) const = 0;
+ virtual void GenerateFixClonedCode(io::Printer* printer) const {}
protected:
const Params& params_;
@@ -111,6 +113,15 @@ class FieldGeneratorMap {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
};
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables);
+void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer);
+void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer);
+
} // namespace javanano
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index b5fbcd5f..a33eba1b 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -67,8 +67,15 @@ void UpdateParamsRecursively(Params& params,
file->name(), file->options().java_outer_classname());
}
if (file->options().has_java_package()) {
+ string result = file->options().java_package();
+ if (!file->options().javanano_use_deprecated_package()) {
+ if (!result.empty()) {
+ result += ".";
+ }
+ result += "nano";
+ }
params.set_java_package(
- file->name(), file->options().java_package());
+ file->name(), result);
}
if (file->options().has_java_multiple_files()) {
params.set_java_multiple_files(
@@ -152,6 +159,12 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file,
params.set_ignore_services(option_value == "true");
} else if (option_name == "parcelable_messages") {
params.set_parcelable_messages(option_value == "true");
+ } else if (option_name == "generate_clone") {
+ params.set_generate_clone(option_value == "true");
+ } else if (option_name == "generate_intdefs") {
+ params.set_generate_intdefs(option_value == "true");
+ } else if (option_name == "generate_clear") {
+ params.set_generate_clear(option_value == "true");
} else {
*error = "Ignore unknown javanano generator option: " + option_name;
}
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index 2149418a..5465655f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -154,6 +154,14 @@ string UnderscoresToCamelCase(const MethodDescriptor* method) {
return UnderscoresToCamelCaseImpl(method->name(), false);
}
+string UnderscoresToCamelCase(const OneofDescriptor* oneof) {
+ return UnderscoresToCamelCaseImpl(oneof->name(), false);
+}
+
+string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof) {
+ return UnderscoresToCamelCaseImpl(oneof->name(), true);
+}
+
string RenameJavaKeywords(const string& input) {
return sRenameKeywords.RenameJavaKeywordsImpl(input);
}
@@ -192,6 +200,14 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) {
if (!result.empty()) result += '.';
result += file->package();
}
+
+ if (!file->options().javanano_use_deprecated_package()) {
+ if (!result.empty()) {
+ result += ".";
+ }
+ result += "nano";
+ }
+
return result;
}
}
@@ -560,6 +576,17 @@ void SetBitOperationVariables(const string name,
(*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
}
+bool HasMapField(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
+ IsMapEntry(field->message_type())) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace javanano
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h
index 29310743..014c85ae 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.h
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h
@@ -54,7 +54,9 @@ extern const char kThinSeparator[];
// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
// "fooBarBaz" or "FooBarBaz", respectively.
string UnderscoresToCamelCase(const FieldDescriptor* field);
+string UnderscoresToCamelCase(const OneofDescriptor* oneof);
string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
+string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof);
// Appends an "_" to the end of a field where the name is a reserved java
// keyword. For example int32 public = 1 will generate int public_.
@@ -181,6 +183,14 @@ string GenerateDifferentBit(int bit_index);
void SetBitOperationVariables(const string name,
int bitIndex, map<string, string>* variables);
+inline bool IsMapEntry(const Descriptor* descriptor) {
+ // TODO(liujisi): Add an option to turn on maps for proto2 syntax as well.
+ return descriptor->options().map_entry() &&
+ descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+bool HasMapField(const Descriptor* descriptor);
+
} // namespace javanano
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.cc b/src/google/protobuf/compiler/javanano/javanano_map_field.cc
new file mode 100644
index 00000000..83b2b0ce
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_map_field.cc
@@ -0,0 +1,186 @@
+// 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.
+
+#include <google/protobuf/compiler/javanano/javanano_map_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+string TypeName(const Params& params, const FieldDescriptor* field,
+ bool boxed) {
+ JavaType java_type = GetJavaType(field);
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ return ClassName(params, field->message_type());
+ case JAVATYPE_INT:
+ case JAVATYPE_LONG:
+ case JAVATYPE_FLOAT:
+ case JAVATYPE_DOUBLE:
+ case JAVATYPE_BOOLEAN:
+ case JAVATYPE_STRING:
+ case JAVATYPE_BYTES:
+ case JAVATYPE_ENUM:
+ if (boxed) {
+ return BoxedPrimitiveTypeName(java_type);
+ } else {
+ return PrimitiveTypeName(java_type);
+ }
+ // No default because we want the compiler to complain if any new JavaTypes
+ // are added..
+ }
+
+ GOOGLE_LOG(FATAL) << "should not reach here.";
+ return "";
+}
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ GOOGLE_CHECK(message->options().map_entry());
+ return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ GOOGLE_CHECK(message->options().map_entry());
+ return message->FindFieldByName("value");
+}
+
+void SetMapVariables(const Params& params,
+ const FieldDescriptor* descriptor, map<string, string>* variables) {
+ const FieldDescriptor* key = KeyField(descriptor);
+ const FieldDescriptor* value = ValueField(descriptor);
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["key_type"] = TypeName(params, key, false);
+ (*variables)["boxed_key_type"] = TypeName(params,key, true);
+ (*variables)["key_desc_type"] =
+ "TYPE_" + ToUpper(FieldDescriptor::TypeName(key->type()));
+ (*variables)["key_tag"] = SimpleItoa(internal::WireFormat::MakeTag(key));
+ (*variables)["value_type"] = TypeName(params, value, false);
+ (*variables)["boxed_value_type"] = TypeName(params, value, true);
+ (*variables)["value_desc_type"] =
+ "TYPE_" + ToUpper(FieldDescriptor::TypeName(value->type()));
+ (*variables)["value_tag"] = SimpleItoa(internal::WireFormat::MakeTag(value));
+ (*variables)["type_parameters"] =
+ (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+ (*variables)["value_default"] =
+ value->type() == FieldDescriptor::TYPE_MESSAGE
+ ? "new " + (*variables)["value_type"] + "()"
+ : "null";
+}
+} // namespace
+
+// ===================================================================
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMapVariables(params, descriptor, &variables_);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public java.util.Map<$type_parameters$> $name$;\n");
+}
+
+void MapFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = null;\n");
+}
+
+void MapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "this.$name$ = com.google.protobuf.nano.InternalNano.mergeMapEntry(\n"
+ " input, this.$name$, mapFactory,\n"
+ " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+ " com.google.protobuf.nano.InternalNano.$value_desc_type$,\n"
+ " $value_default$,\n"
+ " $key_tag$, $value_tag$);\n"
+ "\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " com.google.protobuf.nano.InternalNano.serializeMapField(\n"
+ " output, this.$name$, $number$,\n"
+ " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+ " com.google.protobuf.nano.InternalNano.$value_desc_type$);\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " size += com.google.protobuf.nano.InternalNano.computeMapFieldSize(\n"
+ " this.$name$, $number$,\n"
+ " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+ " com.google.protobuf.nano.InternalNano.$value_desc_type$);\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result +\n"
+ " com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.h b/src/google/protobuf/compiler/javanano/javanano_map_field.h
new file mode 100644
index 00000000..c01bde38
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_map_field.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+#include <vector>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+ explicit MapFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~MapFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index 7c52ca31..a41da5ae 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -90,6 +90,7 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
MessageGenerator(descriptor_->nested_type(i), params_)
.GenerateStaticVariables(printer);
}
@@ -100,6 +101,7 @@ void MessageGenerator::GenerateStaticVariableInitializers(
// Generate static member initializers for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
MessageGenerator(descriptor_->nested_type(i), params_)
.GenerateStaticVariableInitializers(printer);
}
@@ -134,21 +136,37 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
if (params_.store_unknown_fields() && params_.parcelable_messages()) {
printer->Print(
- " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
+ " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$>",
"classname", descriptor_->name());
} else if (params_.store_unknown_fields()) {
printer->Print(
- " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+ " com.google.protobuf.nano.ExtendableMessageNano<$classname$>",
"classname", descriptor_->name());
} else if (params_.parcelable_messages()) {
printer->Print(
- " com.google.protobuf.nano.android.ParcelableMessageNano {\n");
+ " com.google.protobuf.nano.android.ParcelableMessageNano");
} else {
printer->Print(
- " com.google.protobuf.nano.MessageNano {\n");
+ " com.google.protobuf.nano.MessageNano");
+ }
+ if (params_.generate_clone()) {
+ printer->Print(" implements java.lang.Cloneable {\n");
+ } else {
+ printer->Print(" {\n");
}
printer->Indent();
+ if (params_.parcelable_messages()) {
+ printer->Print(
+ "\n"
+ "// Used by Parcelable\n"
+ "@SuppressWarnings({\"unused\"})\n"
+ "public static final android.os.Parcelable.Creator<$classname$> CREATOR =\n"
+ " new com.google.protobuf.nano.android.ParcelableMessageNanoCreator<\n"
+ " $classname$>($classname$.class);\n",
+ "classname", descriptor_->name());
+ }
+
// Nested types and extensions
for (int i = 0; i < descriptor_->extension_count(); i++) {
ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
@@ -159,9 +177,44 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
}
+ // oneof
+ map<string, string> vars;
+ vars["message_name"] = descriptor_->name();
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof_desc = descriptor_->oneof_decl(i);
+ vars["oneof_name"] = UnderscoresToCamelCase(oneof_desc);
+ vars["oneof_capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(oneof_desc);
+ vars["oneof_index"] = SimpleItoa(oneof_desc->index());
+ // Oneof Constants
+ for (int j = 0; j < oneof_desc->field_count(); j++) {
+ const FieldDescriptor* field = oneof_desc->field(j);
+ vars["number"] = SimpleItoa(field->number());
+ vars["cap_field_name"] = ToUpper(field->name());
+ printer->Print(vars,
+ "public static final int $cap_field_name$_FIELD_NUMBER = $number$;\n");
+ }
+ // oneofCase_ and oneof_
+ printer->Print(vars,
+ "private int $oneof_name$Case_ = 0;\n"
+ "private java.lang.Object $oneof_name$_;\n");
+ printer->Print(vars,
+ "public int get$oneof_capitalized_name$Case() {\n"
+ " return this.$oneof_name$Case_;\n"
+ "}\n");
+ // Oneof clear
+ printer->Print(vars,
+ "public $message_name$ clear$oneof_capitalized_name$() {\n"
+ " this.$oneof_name$Case_ = 0;\n"
+ " this.$oneof_name$_ = null;\n"
+ " return this;\n"
+ "}\n");
+ }
+
// Lazy initialization of otherwise static final fields can help prevent the
// class initializer from being generated. We want to prevent it because it
// stops ProGuard from inlining any methods in this class into call sites and
@@ -251,20 +304,28 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
printer->Print("}\n");
} else {
+ printer->Print(
+ "\n"
+ "public $classname$() {\n",
+ "classname", descriptor_->name());
if (params_.generate_clear()) {
- printer->Print(
- "\n"
- "public $classname$() {\n"
- " clear();\n"
- "}\n",
- "classname", descriptor_->name());
+ printer->Print(" clear();\n");
+ } else {
+ printer->Indent();
+ GenerateFieldInitializers(printer);
+ printer->Outdent();
}
+ printer->Print("}\n");
}
// Other methods in this class
GenerateClear(printer);
+ if (params_.generate_clone()) {
+ GenerateClone(printer);
+ }
+
if (params_.generate_equals()) {
GenerateEquals(printer);
GenerateHashCode(printer);
@@ -342,6 +403,11 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
"classname", descriptor_->name());
printer->Indent();
+ if (HasMapField(descriptor_)) {
+ printer->Print(
+ "com.google.protobuf.nano.MapFactories.MapFactory mapFactory =\n"
+ " com.google.protobuf.nano.MapFactories.getMapFactory();\n");
+ }
printer->Print(
"while (true) {\n");
@@ -453,6 +519,15 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
"classname", descriptor_->name());
printer->Indent();
+ GenerateFieldInitializers(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " return this;\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateFieldInitializers(io::Printer* printer) {
// Clear bit fields.
int totalInts = (field_generators_.total_bits() + 31) / 32;
for (int i = 0; i < totalInts; i++) {
@@ -466,16 +541,46 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
field_generators_.get(field).GenerateClearCode(printer);
}
+ // Clear oneofs.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "clear$oneof_capitalized_name$();\n",
+ "oneof_capitalized_name", UnderscoresToCapitalizedCamelCase(
+ descriptor_->oneof_decl(i)));
+ }
+
// Clear unknown fields.
if (params_.store_unknown_fields()) {
printer->Print("unknownFieldData = null;\n");
}
+ printer->Print("cachedSize = -1;\n");
+}
+
+void MessageGenerator::GenerateClone(io::Printer* printer) {
+ printer->Print(
+ "@Override\n"
+ "public $classname$ clone() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ printer->Print(
+ "$classname$ cloned;\n"
+ "try {\n"
+ " cloned = ($classname$) super.clone();\n"
+ "} catch (java.lang.CloneNotSupportedException e) {\n"
+ " throw new java.lang.AssertionError(e);\n"
+ "}\n",
+ "classname", descriptor_->name());
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i)).GenerateFixClonedCode(printer);
+ }
printer->Outdent();
printer->Print(
- " cachedSize = -1;\n"
- " return this;\n"
- "}\n");
+ " return cloned;\n"
+ "}\n"
+ "\n");
}
void MessageGenerator::GenerateEquals(io::Printer* printer) {
@@ -501,6 +606,16 @@ void MessageGenerator::GenerateEquals(io::Printer* printer) {
"$classname$ other = ($classname$) o;\n",
"classname", descriptor_->name());
+ // Checking oneof case before checking each oneof field.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof_desc = descriptor_->oneof_decl(i);
+ printer->Print(
+ "if (this.$oneof_name$Case_ != other.$oneof_name$Case_) {\n"
+ " return false;\n"
+ "}\n",
+ "oneof_name", UnderscoresToCamelCase(oneof_desc));
+ }
+
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
field_generators_.get(field).GenerateEqualsCode(printer);
@@ -508,7 +623,11 @@ void MessageGenerator::GenerateEquals(io::Printer* printer) {
if (params_.store_unknown_fields()) {
printer->Print(
- "return unknownFieldDataEquals(other);\n");
+ "if (unknownFieldData == null || unknownFieldData.isEmpty()) {\n"
+ " return other.unknownFieldData == null || other.unknownFieldData.isEmpty();\n"
+ "} else {\n"
+ " return unknownFieldData.equals(other.unknownFieldData);\n"
+ "}");
} else {
printer->Print(
"return true;\n");
@@ -538,7 +657,9 @@ void MessageGenerator::GenerateHashCode(io::Printer* printer) {
if (params_.store_unknown_fields()) {
printer->Print(
- "result = 31 * result + unknownFieldDataHashCode();\n");
+ "result = 31 * result + \n"
+ " (unknownFieldData == null || unknownFieldData.isEmpty() ? 0 : \n"
+ " unknownFieldData.hashCode());\n");
}
printer->Print("return result;\n");
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
index 6f25a3a0..281ec64f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -77,8 +77,10 @@ class MessageGenerator {
const FieldDescriptor* field);
void GenerateClear(io::Printer* printer);
+ void GenerateFieldInitializers(io::Printer* printer);
void GenerateEquals(io::Printer* printer);
void GenerateHashCode(io::Printer* printer);
+ void GenerateClone(io::Printer* printer);
const Params& params_;
const Descriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
index a46081d0..d1d04b52 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -127,6 +127,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void MessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " cloned.$name$ = this.$name$.clone();\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"if (this.$name$ == null) { \n"
@@ -146,12 +154,95 @@ GenerateHashCodeCode(io::Printer* printer) const {
"result = 31 * result +\n"
" (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
}
+// ===================================================================
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMessageVariables(params, descriptor, &variables_);
+ SetCommonOneofVariables(descriptor, &variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
+
+void MessageOneofFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case$;\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case$) {\n"
+ " return ($type$) this.$oneof_name$_;\n"
+ " }\n"
+ " return null;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$($type$ value) {\n"
+ " if (value == null) { throw new java.lang.NullPointerException(); }\n"
+ " $set_oneof_case$;\n"
+ " this.$oneof_name$_ = value;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ // No clear method for oneof fields.
+}
+
+void MessageOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!($has_oneof_case$)) {\n"
+ " this.$oneof_name$_ = new $type$();\n"
+ "}\n"
+ "input.readMessage(\n"
+ " (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+ "$set_oneof_case$;\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " output.writeMessage($number$,\n"
+ " (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeMessageSize($number$,\n"
+ " (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$oneof_name$ != null) {\n"
+ " cloned.$oneof_name$ = this.$oneof_name$.clone();\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ GenerateOneofFieldEquals(descriptor_, variables_, printer);
+}
+
+void MessageOneofFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ GenerateOneofFieldHashCode(descriptor_, variables_, printer);
+}
// ===================================================================
-RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
- : FieldGenerator(params), descriptor_(descriptor) {
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
SetMessageVariables(params, descriptor, &variables_);
}
@@ -238,6 +329,19 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void RepeatedMessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " cloned.$name$ = new $type$[this.$name$.length];\n"
+ " for (int i = 0; i < this.$name$.length; i++) {\n"
+ " if (this.$name$[i] != null) {\n"
+ " cloned.$name$[i] = this.$name$[i].clone();\n"
+ " }\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
index 5d35fd24..e074735c 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -58,6 +58,7 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -66,6 +67,29 @@ class MessageFieldGenerator : public FieldGenerator {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
};
+class MessageOneofFieldGenerator : public FieldGenerator {
+ public:
+ explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params);
+ ~MessageOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
class RepeatedMessageFieldGenerator : public FieldGenerator {
public:
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
@@ -80,6 +104,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
index 4691f360..e3b4bb93 100644
--- a/src/google/protobuf/compiler/javanano/javanano_params.h
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -66,6 +66,8 @@ class Params {
bool parcelable_messages_;
bool reftypes_primitive_enums_;
bool generate_clear_;
+ bool generate_clone_;
+ bool generate_intdefs_;
public:
Params(const string & base_name) :
@@ -81,7 +83,9 @@ class Params {
ignore_services_(false),
parcelable_messages_(false),
reftypes_primitive_enums_(false),
- generate_clear_(true) {
+ generate_clear_(true),
+ generate_clone_(false),
+ generate_intdefs_(false) {
}
const string& base_name() const {
@@ -231,6 +235,20 @@ class Params {
bool generate_clear() const {
return generate_clear_;
}
+
+ void set_generate_clone(bool value) {
+ generate_clone_ = value;
+ }
+ bool generate_clone() const {
+ return generate_clone_;
+ }
+
+ void set_generate_intdefs(bool value) {
+ generate_intdefs_ = value;
+ }
+ bool generate_intdefs() const {
+ return generate_intdefs_;
+ }
};
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index a3bc3a84..978abf2c 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -155,28 +155,6 @@ int FixedSize(FieldDescriptor::Type type) {
return -1;
}
-// Return true if the type is a that has variable length
-// for instance String's.
-bool IsVariableLenType(JavaType type) {
- switch (type) {
- case JAVATYPE_INT : return false;
- case JAVATYPE_LONG : return false;
- case JAVATYPE_FLOAT : return false;
- case JAVATYPE_DOUBLE : return false;
- case JAVATYPE_BOOLEAN: return false;
- case JAVATYPE_STRING : return true;
- case JAVATYPE_BYTES : return true;
- case JAVATYPE_ENUM : return false;
- case JAVATYPE_MESSAGE: return true;
-
- // No default because we want the compiler to complain if any new
- // JavaTypes are added.
- }
-
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return false;
-}
-
bool AllAscii(const string& text) {
for (int i = 0; i < text.size(); i++) {
if ((text[i] & 0x80) != 0) {
@@ -186,6 +164,7 @@ bool AllAscii(const string& text) {
return true;
}
+
void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params,
map<string, string>* variables) {
(*variables)["name"] =
@@ -385,6 +364,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
}
+void RepeatedPrimitiveFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " cloned.$name$ = this.$name$.clone();\n"
+ "}\n");
+}
+
void PrimitiveFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
// We define equality as serialized form equality. If generate_has(),
@@ -706,8 +693,79 @@ GenerateHashCodeCode(io::Printer* printer) const {
// ===================================================================
-RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+ SetCommonOneofVariables(descriptor, &variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
+
+void PrimitiveOneofFieldGenerator::GenerateMembers(
+ io::Printer* printer, bool /*unused lazy_init*/) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case$;\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case$) {\n"
+ " return ($type$) ($boxed_type$) this.$oneof_name$_;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$($type$ value) {\n"
+ " $set_oneof_case$;\n"
+ " this.$oneof_name$_ = value;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateClearCode(
+ io::Printer* printer) const {
+ // No clear method for oneof fields.
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMergingCode(
+ io::Printer* printer) const {
+ printer->Print(variables_,
+ "this.$oneof_name$_ = input.read$capitalized_type$();\n"
+ "$set_oneof_case$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSerializationCode(
+ io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " output.write$capitalized_type$(\n"
+ " $number$, ($boxed_type$) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSerializedSizeCode(
+ io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size(\n"
+ " $number$, ($boxed_type$) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateEqualsCode(
+ io::Printer* printer) const {
+ GenerateOneofFieldEquals(descriptor_, variables_, printer);
+}
+
+void PrimitiveOneofFieldGenerator::GenerateHashCodeCode(
+ io::Printer* printer) const {
+ GenerateOneofFieldHashCode(descriptor_, variables_, printer);
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
: FieldGenerator(params), descriptor_(descriptor) {
SetPrimitiveVariables(descriptor, params, &variables_);
}
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
index c04a19b7..a01981dd 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -47,7 +47,7 @@ namespace javanano {
class PrimitiveFieldGenerator : public FieldGenerator {
public:
explicit PrimitiveFieldGenerator(
- const FieldDescriptor* descriptor, const Params &params);
+ const FieldDescriptor* descriptor, const Params& params);
~PrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
@@ -94,9 +94,32 @@ class AccessorPrimitiveFieldGenerator : public FieldGenerator {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorPrimitiveFieldGenerator);
};
+class PrimitiveOneofFieldGenerator : public FieldGenerator {
+ public:
+ explicit PrimitiveOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~PrimitiveOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params);
~RepeatedPrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
@@ -108,6 +131,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 931b8fa3..4815a726 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -36,6 +36,8 @@
#include <google/protobuf/compiler/java/java_generator.h>
#include <google/protobuf/compiler/javanano/javanano_generator.h>
#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
int main(int argc, char* argv[]) {
@@ -68,5 +70,15 @@ int main(int argc, char* argv[]) {
cli.RegisterGenerator("--ruby_out", &rb_generator,
"Generate Ruby source file.");
+ // CSharp
+ google::protobuf::compiler::csharp::Generator csharp_generator;
+ cli.RegisterGenerator("--csharp_out", &csharp_generator,
+ "Generate C# source file.");
+
+ // Objective C
+ google::protobuf::compiler::objectivec::ObjectiveCGenerator objc_generator;
+ cli.RegisterGenerator("--objc_out", &objc_generator,
+ "Generate Objective C header and source.");
+
return cli.Run(argc, argv);
}
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index e7d5117e..98261431 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -133,10 +133,10 @@ bool MockCodeGenerator::Generate(
*error = "Saw message type MockCodeGenerator_Error.";
return false;
} else if (command == "Exit") {
- cerr << "Saw message type MockCodeGenerator_Exit." << endl;
+ std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl;
exit(123);
} else if (command == "Abort") {
- cerr << "Saw message type MockCodeGenerator_Abort." << endl;
+ std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl;
abort();
} else if (command == "HasSourceCodeInfo") {
FileDescriptorProto file_descriptor_proto;
@@ -144,8 +144,8 @@ bool MockCodeGenerator::Generate(
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;
+ std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
+ << has_source_code_info << "." << std::endl;
abort();
} else {
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
new file mode 100644
index 00000000..d6f01c60
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
@@ -0,0 +1,198 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
+ : descriptor_(descriptor),
+ name_(EnumName(descriptor_)) {
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ const EnumValueDescriptor* value = descriptor_->value(i);
+ const EnumValueDescriptor* canonical_value =
+ descriptor_->FindValueByNumber(value->number());
+
+ if (value == canonical_value) {
+ base_values_.push_back(value);
+ }
+ all_values_.push_back(value);
+ }
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::GenerateHeader(io::Printer* printer) {
+ string enum_comments;
+ SourceLocation location;
+ if (descriptor_->GetSourceLocation(&location)) {
+ enum_comments = BuildCommentsString(location);
+ } else {
+ enum_comments = "";
+ }
+
+ printer->Print(
+ "#pragma mark - Enum $name$\n"
+ "\n",
+ "name", name_);
+
+ printer->Print("$comments$typedef GPB_ENUM($name$) {\n",
+ "comments", enum_comments,
+ "name", name_);
+ printer->Indent();
+
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ // Include the unknown value.
+ printer->Print(
+ "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n",
+ "name", name_);
+ }
+
+ for (int i = 0; i < all_values_.size(); i++) {
+ SourceLocation location;
+ if (all_values_[i]->GetSourceLocation(&location)) {
+ string comments = BuildCommentsString(location).c_str();
+ if (comments.length() > 0) {
+ if (i > 0) {
+ printer->Print("\n");
+ }
+ printer->Print(comments.c_str());
+ }
+ }
+
+ printer->Print(
+ "$name$ = $value$,\n",
+ "name", EnumValueName(all_values_[i]),
+ "value", SimpleItoa(all_values_[i]->number()));
+ }
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n"
+ "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n"
+ "\n"
+ "BOOL $name$_IsValidValue(int32_t value);\n"
+ "\n",
+ "name", name_);
+}
+
+void EnumGenerator::GenerateSource(io::Printer* printer) {
+ printer->Print(
+ "#pragma mark - Enum $name$\n"
+ "\n",
+ "name", name_);
+
+ printer->Print(
+ "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n"
+ " static GPBEnumDescriptor *descriptor = NULL;\n"
+ " if (!descriptor) {\n"
+ " static GPBMessageEnumValueDescription values[] = {\n",
+ "name", name_);
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+
+ // Note: For the TextFormat decode info, we can't use the enum value as
+ // the key because protocol buffer enums have 'allow_alias', which lets
+ // a value be used more than once. Instead, the index into the list of
+ // enum value descriptions is used. Note: start with -1 so the first one
+ // will be zero.
+ TextFormatDecodeData text_format_decode_data;
+ int enum_value_description_key = -1;
+
+ for (int i = 0; i < all_values_.size(); i++) {
+ ++enum_value_description_key;
+ string short_name(EnumValueShortName(all_values_[i]));
+ printer->Print("{ .name = \"$short_name$\", .number = $name$ },\n",
+ "short_name", short_name,
+ "name", EnumValueName(all_values_[i]));
+ if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) {
+ text_format_decode_data.AddString(enum_value_description_key, short_name,
+ all_values_[i]->name());
+ }
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(" };\n");
+ if (text_format_decode_data.num_entries() == 0) {
+ printer->Print(
+ " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+ " values:values\n"
+ " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n"
+ " enumVerifier:$name$_IsValidValue];\n",
+ "name", name_);
+ } else {
+ printer->Print(
+ " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
+ " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+ " values:values\n"
+ " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n"
+ " enumVerifier:$name$_IsValidValue\n"
+ " extraTextFormatInfo:extraTextFormatInfo];\n",
+ "name", name_,
+ "extraTextFormatInfo", CEscape(text_format_decode_data.Data()));
+ }
+ printer->Print(
+ " }\n"
+ " return descriptor;\n"
+ "}\n\n");
+
+ printer->Print(
+ "BOOL $name$_IsValidValue(int32_t value__) {\n"
+ " switch (value__) {\n",
+ "name", name_);
+
+ for (int i = 0; i < base_values_.size(); i++) {
+ printer->Print(
+ " case $name$:\n",
+ "name", EnumValueName(base_values_[i]));
+ }
+
+ printer->Print(
+ " return YES;\n"
+ " default:\n"
+ " return NO;\n"
+ " }\n"
+ "}\n\n");
+}
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
new file mode 100644
index 00000000..0b41cf73
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer; // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumGenerator {
+ public:
+ explicit EnumGenerator(const EnumDescriptor* descriptor);
+ ~EnumGenerator();
+
+ void GenerateHeader(io::Printer* printer);
+ void GenerateSource(io::Printer* printer);
+
+ const string& name() const { return name_; }
+
+ private:
+ const EnumDescriptor* descriptor_;
+ vector<const EnumValueDescriptor*> base_values_;
+ vector<const EnumValueDescriptor*> all_values_;
+ const string name_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
new file mode 100644
index 00000000..30a13ddb
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
@@ -0,0 +1,144 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+void SetEnumVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ string type = EnumName(descriptor->enum_type());
+ (*variables)["storage_type"] = type;
+ // For non repeated fields, if it was defined in a different file, the
+ // property decls need to use "enum NAME" rather than just "NAME" to support
+ // the forward declaration of the enums.
+ if (!descriptor->is_repeated() &&
+ (descriptor->file() != descriptor->enum_type()->file())) {
+ (*variables)["property_type"] = "enum " + type;
+ }
+ (*variables)["enum_verifier"] = type + "_IsValidValue";
+ (*variables)["enum_desc_func"] = type + "_EnumDescriptor";
+
+ const Descriptor* msg_descriptor = descriptor->containing_type();
+ (*variables)["owning_message_class"] = ClassName(msg_descriptor);
+}
+} // namespace
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor)
+ : SingleFieldGenerator(descriptor) {
+ SetEnumVariables(descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::GenerateFieldDescriptionTypeSpecific(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n");
+}
+
+void EnumFieldGenerator::GenerateCFunctionDeclarations(
+ io::Printer* printer) const {
+ if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ return;
+ }
+
+ printer->Print(
+ variables_,
+ "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n"
+ "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n"
+ "\n");
+}
+
+void EnumFieldGenerator::GenerateCFunctionImplementations(
+ io::Printer* printer) const {
+ if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return;
+
+ printer->Print(
+ variables_,
+ "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {\n"
+ " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n"
+ " GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n"
+ " return GPBGetMessageInt32Field(message, field);\n"
+ "}\n"
+ "\n"
+ "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value) {\n"
+ " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n"
+ " GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n"
+ " GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);\n"
+ "}\n"
+ "\n");
+}
+
+void EnumFieldGenerator::DetermineForwardDeclarations(
+ set<string>* fwd_decls) const {
+ // If it is an enum defined in a different file, then we'll need a forward
+ // declaration for it. When it is in our file, all the enums are output
+ // before the message, so it will be declared before it is needed.
+ if (descriptor_->file() != descriptor_->enum_type()->file()) {
+ // Enum name is already in "storage_type".
+ const string& name = variable("storage_type");
+ fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")");
+ }
+}
+
+RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : RepeatedFieldGenerator(descriptor) {
+ SetEnumVariables(descriptor, &variables_);
+ variables_["array_storage_type"] = "GPBEnumArray";
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n");
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
new file mode 100644
index 00000000..b629eae8
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumFieldGenerator : public SingleFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ public:
+ virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+ virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+ virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+ virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ protected:
+ explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~EnumFieldGenerator();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ public:
+ virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+
+ protected:
+ RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~RepeatedEnumFieldGenerator();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
new file mode 100644
index 00000000..4e348393
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
@@ -0,0 +1,136 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <iostream>
+
+#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+ExtensionGenerator::ExtensionGenerator(const string& root_class_name,
+ const FieldDescriptor* descriptor)
+ : method_name_(ExtensionMethodName(descriptor)),
+ root_class_and_method_name_(root_class_name + "_" + method_name_),
+ descriptor_(descriptor) {
+ if (descriptor->is_map()) {
+ // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+ // error cases, so it seems to be ok to use as a back door for errors.
+ cerr << "error: Extension is a map<>!"
+ << " That used to be blocked by the compiler." << endl;
+ cerr.flush();
+ abort();
+ }
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) {
+ map<string, string> vars;
+ vars["method_name"] = method_name_;
+ SourceLocation location;
+ if (descriptor_->GetSourceLocation(&location)) {
+ vars["comments"] = BuildCommentsString(location);
+ } else {
+ vars["comments"] = "";
+ }
+ printer->Print(vars,
+ "$comments$"
+ "+ (GPBExtensionDescriptor *)$method_name$;\n");
+}
+
+void ExtensionGenerator::GenerateStaticVariablesInitialization(
+ io::Printer* printer) {
+ map<string, string> vars;
+ vars["root_class_and_method_name"] = root_class_and_method_name_;
+ vars["extended_type"] = ClassName(descriptor_->containing_type());
+ vars["number"] = SimpleItoa(descriptor_->number());
+
+ std::vector<string> options;
+ if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated");
+ if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked");
+ if (descriptor_->containing_type()->options().message_set_wire_format())
+ options.push_back("GPBExtensionSetWireFormat");
+
+ vars["options"] = BuildFlagsString(options);
+
+ ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
+ string singular_type;
+ if (objc_type == OBJECTIVECTYPE_MESSAGE) {
+ vars["type"] = string("GPBStringifySymbol(") +
+ ClassName(descriptor_->message_type()) + ")";
+ } else {
+ vars["type"] = "NULL";
+ }
+
+ vars["default_name"] = GPBGenericValueFieldName(descriptor_);
+ if (descriptor_->is_repeated()) {
+ vars["default"] = "nil";
+ } else {
+ vars["default"] = DefaultValue(descriptor_);
+ }
+ string type = GetCapitalizedType(descriptor_);
+ vars["extension_type"] = string("GPBDataType") + type;
+
+ if (objc_type == OBJECTIVECTYPE_ENUM) {
+ vars["enum_desc_func_name"] =
+ EnumName(descriptor_->enum_type()) + "_EnumDescriptor";
+ } else {
+ vars["enum_desc_func_name"] = "NULL";
+ }
+
+ printer->Print(vars,
+ "{\n"
+ " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n"
+ " .dataType = $extension_type$,\n"
+ " .extendedClass = GPBStringifySymbol($extended_type$),\n"
+ " .fieldNumber = $number$,\n"
+ " .defaultValue.$default_name$ = $default$,\n"
+ " .messageOrGroupClassName = $type$,\n"
+ " .options = $options$,\n"
+ " .enumDescriptorFunc = $enum_desc_func_name$,\n"
+ "},\n");
+}
+
+void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) {
+ printer->Print(
+ "[registry addExtension:$root_class_and_method_name$];\n",
+ "root_class_and_method_name", root_class_and_method_name_);
+}
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/src/google/protobuf/compiler/objectivec/objectivec_extension.h
new file mode 100644
index 00000000..e361e639
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.h
@@ -0,0 +1,69 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class FieldDescriptor; // descriptor.h
+namespace io {
+class Printer; // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class ExtensionGenerator {
+ public:
+ ExtensionGenerator(const string& root_class_name,
+ const FieldDescriptor* descriptor);
+ ~ExtensionGenerator();
+
+ void GenerateMembersHeader(io::Printer* printer);
+ void GenerateStaticVariablesInitialization(io::Printer* printer);
+ void GenerateRegistrationSource(io::Printer* printer);
+
+ private:
+ string method_name_;
+ string root_class_and_method_name_;
+ const FieldDescriptor* descriptor_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
new file mode 100644
index 00000000..cf5d8cfb
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -0,0 +1,434 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ string camel_case_name = FieldName(descriptor);
+ string raw_field_name;
+ if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
+ raw_field_name = descriptor->message_type()->name();
+ } else {
+ raw_field_name = descriptor->name();
+ }
+ // The logic here has to match -[GGPBFieldDescriptor textFormatName].
+ const string un_camel_case_name(
+ UnCamelCaseFieldName(camel_case_name, descriptor));
+ const bool needs_custom_name = (raw_field_name != un_camel_case_name);
+
+ SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ (*variables)["comments"] = BuildCommentsString(location);
+ } else {
+ (*variables)["comments"] = "\n";
+ }
+ const string& classname = ClassName(descriptor->containing_type());
+ (*variables)["classname"] = classname;
+ (*variables)["name"] = camel_case_name;
+ const string& capitalized_name = FieldNameCapitalized(descriptor);
+ (*variables)["capitalized_name"] = capitalized_name;
+ (*variables)["raw_field_name"] = raw_field_name;
+ (*variables)["field_number_name"] =
+ classname + "_FieldNumber_" + capitalized_name;
+ (*variables)["field_number"] = SimpleItoa(descriptor->number());
+ (*variables)["has_index"] = SimpleItoa(descriptor->index());
+ (*variables)["field_type"] = GetCapitalizedType(descriptor);
+ std::vector<string> field_flags;
+ if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated");
+ if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired");
+ if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional");
+ if (descriptor->is_packed()) field_flags.push_back("GPBFieldPacked");
+
+ // ObjC custom flags.
+ if (descriptor->has_default_value())
+ field_flags.push_back("GPBFieldHasDefaultValue");
+ if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom");
+ if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
+ field_flags.push_back("GPBFieldHasEnumDescriptor");
+ }
+
+ (*variables)["fieldflags"] = BuildFlagsString(field_flags);
+
+ (*variables)["default"] = DefaultValue(descriptor);
+ (*variables)["default_name"] = GPBGenericValueFieldName(descriptor);
+
+ (*variables)["dataTypeSpecific_name"] = "className";
+ (*variables)["dataTypeSpecific_value"] = "NULL";
+
+ string field_options = descriptor->options().SerializeAsString();
+ // Must convert to a standard byte order for packing length into
+ // a cstring.
+ uint32 length = ghtonl(field_options.length());
+ if (length > 0) {
+ string bytes((const char*)&length, sizeof(length));
+ bytes.append(field_options);
+ string options_str = "\"" + CEscape(bytes) + "\"";
+ (*variables)["fieldoptions"] = "\"" + CEscape(bytes) + "\"";
+ } else {
+ (*variables)["fieldoptions"] = "";
+ }
+
+ // Clear some common things so they can be set just when needed.
+ (*variables)["storage_attribute"] = "";
+}
+
+} // namespace
+
+FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) {
+ FieldGenerator* result = NULL;
+ if (field->is_repeated()) {
+ switch (GetObjectiveCType(field)) {
+ case OBJECTIVECTYPE_MESSAGE: {
+ if (field->is_map()) {
+ result = new MapFieldGenerator(field);
+ } else {
+ result = new RepeatedMessageFieldGenerator(field);
+ }
+ break;
+ }
+ case OBJECTIVECTYPE_ENUM:
+ result = new RepeatedEnumFieldGenerator(field);
+ break;
+ default:
+ result = new RepeatedPrimitiveFieldGenerator(field);
+ break;
+ }
+ } else {
+ switch (GetObjectiveCType(field)) {
+ case OBJECTIVECTYPE_MESSAGE: {
+ result = new MessageFieldGenerator(field);
+ break;
+ }
+ case OBJECTIVECTYPE_ENUM:
+ result = new EnumFieldGenerator(field);
+ break;
+ default:
+ if (IsReferenceType(field)) {
+ result = new PrimitiveObjFieldGenerator(field);
+ } else {
+ result = new PrimitiveFieldGenerator(field);
+ }
+ break;
+ }
+ }
+ result->FinishInitialization();
+ return result;
+}
+
+
+FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetCommonFieldVariables(descriptor, &variables_);
+}
+
+FieldGenerator::~FieldGenerator() {}
+
+void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "$field_number_name$ = $field_number$,\n");
+}
+
+void FieldGenerator::GenerateCFunctionDeclarations(
+ io::Printer* printer) const {
+ // Nothing
+}
+
+void FieldGenerator::GenerateCFunctionImplementations(
+ io::Printer* printer) const {
+ // Nothing
+}
+
+void FieldGenerator::DetermineForwardDeclarations(
+ set<string>* fwd_decls) const {
+ // Nothing
+}
+
+void FieldGenerator::GenerateFieldDescription(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "{\n"
+ " .name = \"$name$\",\n"
+ " .number = $field_number_name$,\n"
+ " .hasIndex = $has_index$,\n"
+ " .flags = $fieldflags$,\n"
+ " .dataType = GPBDataType$field_type$,\n"
+ " .offset = offsetof($classname$__storage_, $name$),\n"
+ " .defaultValue.$default_name$ = $default$,\n");
+
+ // TODO(thomasvl): It might be useful to add a CPP wrapper to support
+ // compiling away the EnumDescriptors. To do that, we'd need a #if here
+ // to control setting the descriptor vs. the validator, and above in
+ // SetCommonFieldVariables() we'd want to wrap how we add
+ // GPBFieldHasDefaultValue to the flags.
+
+ // " .dataTypeSpecific.value* = [something],"
+ GenerateFieldDescriptionTypeSpecific(printer);
+
+ const string& field_options(variables_.find("fieldoptions")->second);
+ if (field_options.empty()) {
+ printer->Print(" .fieldOptions = NULL,\n");
+ } else {
+ // Can't use PrintRaw() here to get the #if/#else/#endif lines completely
+ // outdented because the need for indent captured on the previous
+ // printing of a \n and there is no way to get the current indent level
+ // to call the right number of Outdent()/Indents() to maintain state.
+ printer->Print(
+ variables_,
+ "#if GPBOBJC_INCLUDE_FIELD_OPTIONS\n"
+ " .fieldOptions = $fieldoptions$,\n"
+ "#else\n"
+ " .fieldOptions = NULL,\n"
+ "#endif // GPBOBJC_INCLUDE_FIELD_OPTIONS\n");
+ }
+
+ printer->Print("},\n");
+}
+
+void FieldGenerator::GenerateFieldDescriptionTypeSpecific(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n");
+}
+
+void FieldGenerator::SetOneofIndexBase(int index_base) {
+ if (descriptor_->containing_oneof() != NULL) {
+ int index = descriptor_->containing_oneof()->index() + index_base;
+ // Flip the sign to mark it as a oneof.
+ variables_["has_index"] = SimpleItoa(-index);
+ }
+}
+
+void FieldGenerator::FinishInitialization(void) {
+ // If "property_type" wasn't set, make it "storage_type".
+ if ((variables_.find("property_type") == variables_.end()) &&
+ (variables_.find("storage_type") != variables_.end())) {
+ variables_["property_type"] = variable("storage_type");
+ }
+}
+
+SingleFieldGenerator::SingleFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : FieldGenerator(descriptor) {
+ // Nothing
+}
+
+SingleFieldGenerator::~SingleFieldGenerator() {}
+
+void SingleFieldGenerator::GenerateFieldStorageDeclaration(
+ io::Printer* printer) const {
+ printer->Print(variables_, "$storage_type$ $name$;\n");
+}
+
+void SingleFieldGenerator::GeneratePropertyDeclaration(
+ io::Printer* printer) const {
+ printer->Print(variables_, "$comments$");
+ if (WantsHasProperty()) {
+ printer->Print(
+ variables_,
+ "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n");
+ }
+ printer->Print(
+ variables_,
+ "@property(nonatomic, readwrite) $property_type$ $name$;\n"
+ "\n");
+}
+
+void SingleFieldGenerator::GeneratePropertyImplementation(
+ io::Printer* printer) const {
+ if (WantsHasProperty()) {
+ printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n");
+ } else {
+ printer->Print(variables_, "@dynamic $name$;\n");
+ }
+}
+
+bool SingleFieldGenerator::WantsHasProperty(void) const {
+ if (descriptor_->containing_oneof() != NULL) {
+ // If in a oneof, it uses the oneofcase instead of a has bit.
+ return false;
+ }
+ if (HasFieldPresence(descriptor_->file())) {
+ // In proto1/proto2, every field has a has_$name$() method.
+ return true;
+ }
+ return false;
+}
+
+ObjCObjFieldGenerator::ObjCObjFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : SingleFieldGenerator(descriptor) {
+ variables_["property_storage_attribute"] = "strong";
+ if (IsRetainedName(variables_["name"])) {
+ variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
+ }
+}
+
+ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {}
+
+void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration(
+ io::Printer* printer) const {
+ printer->Print(variables_, "$storage_type$ *$name$;\n");
+}
+
+void ObjCObjFieldGenerator::GeneratePropertyDeclaration(
+ io::Printer* printer) const {
+
+ // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that
+ // it uses pointers and deals with Objective C's rules around storage name
+ // conventions (init*, new*, etc.)
+
+ printer->Print(variables_, "$comments$");
+ if (WantsHasProperty()) {
+ printer->Print(
+ variables_,
+ "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n");
+ }
+ printer->Print(
+ variables_,
+ "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$;\n");
+ if (IsInitName(variables_.find("name")->second)) {
+ // If property name starts with init we need to annotate it to get past ARC.
+ // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+ printer->Print(variables_,
+ "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
+ }
+ printer->Print("\n");
+}
+
+RepeatedFieldGenerator::RepeatedFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : ObjCObjFieldGenerator(descriptor) {
+ // Repeated fields don't use the has index.
+ variables_["has_index"] = "GPBNoHasBit";
+}
+
+RepeatedFieldGenerator::~RepeatedFieldGenerator() {}
+
+void RepeatedFieldGenerator::FinishInitialization(void) {
+ FieldGenerator::FinishInitialization();
+ variables_["array_comment"] =
+ "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n";
+}
+
+void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
+ io::Printer* printer) const {
+ printer->Print(variables_, "$array_storage_type$ *$name$;\n");
+}
+
+void RepeatedFieldGenerator::GeneratePropertyImplementation(
+ io::Printer* printer) const {
+ printer->Print(variables_, "@dynamic $name$, $name$_Count;\n");
+}
+
+void RepeatedFieldGenerator::GeneratePropertyDeclaration(
+ io::Printer* printer) const {
+
+ // Repeated fields don't need the has* properties, but they do expose a
+ // *Count (to check without autocreation). So for the field property we need
+ // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for
+ // dealing with needing Objective C's rules around storage name conventions
+ // (init*, new*, etc.)
+
+ printer->Print(
+ variables_,
+ "$comments$"
+ "$array_comment$"
+ "@property(nonatomic, readwrite, strong, null_resettable) $array_storage_type$ *$name$$storage_attribute$;\n"
+ "@property(nonatomic, readonly) NSUInteger $name$_Count;\n");
+ if (IsInitName(variables_.find("name")->second)) {
+ // If property name starts with init we need to annotate it to get past ARC.
+ // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+ printer->Print(variables_,
+ "- ($array_storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
+ }
+ printer->Print("\n");
+}
+
+bool RepeatedFieldGenerator::WantsHasProperty(void) const {
+ // Consumer check the array size/existance rather than a has bit.
+ return false;
+}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+ : descriptor_(descriptor),
+ field_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
+ extension_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
+ // Construct all the FieldGenerators.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i)));
+ }
+ for (int i = 0; i < descriptor->extension_count(); i++) {
+ extension_generators_[i].reset(FieldGenerator::Make(descriptor->extension(i)));
+ }
+}
+
+FieldGeneratorMap::~FieldGeneratorMap() {}
+
+const FieldGenerator& FieldGeneratorMap::get(
+ const FieldDescriptor* field) const {
+ GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+ return *field_generators_[field->index()];
+}
+
+const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
+ return *extension_generators_[index];
+}
+
+void FieldGeneratorMap::SetOneofIndexBase(int index_base) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_[i]->SetOneofIndexBase(index_base);
+ }
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h
new file mode 100644
index 00000000..130a52dd
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h
@@ -0,0 +1,168 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class Printer; // printer.h
+} // namespace io
+
+namespace compiler {
+namespace objectivec {
+
+class FieldGenerator {
+ public:
+ static FieldGenerator* Make(const FieldDescriptor* field);
+
+ virtual ~FieldGenerator();
+
+ virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0;
+ virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0;
+
+ virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0;
+
+ virtual void GenerateFieldDescription(io::Printer* printer) const;
+ virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+ virtual void GenerateFieldNumberConstant(io::Printer* printer) const;
+
+ virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+ virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+
+ virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ void SetOneofIndexBase(int index_base);
+
+ string variable(const char* key) const {
+ return variables_.find(key)->second;
+ }
+
+ bool needs_textformat_name_support() const {
+ const string& field_flags = variable("fieldflags");
+ return field_flags.find("GPBFieldTextFormatNameCustom") != string::npos;
+ }
+ string generated_objc_name() const { return variable("name"); }
+ string raw_field_name() const { return variable("raw_field_name"); }
+
+ protected:
+ explicit FieldGenerator(const FieldDescriptor* descriptor);
+
+ virtual void FinishInitialization(void);
+ virtual bool WantsHasProperty(void) const = 0;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+class SingleFieldGenerator : public FieldGenerator {
+ public:
+ virtual ~SingleFieldGenerator();
+
+ virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+ virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
+
+ virtual void GeneratePropertyImplementation(io::Printer* printer) const;
+
+ protected:
+ explicit SingleFieldGenerator(const FieldDescriptor* descriptor);
+ virtual bool WantsHasProperty(void) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingleFieldGenerator);
+};
+
+// Subclass with common support for when the field ends up as an ObjC Object.
+class ObjCObjFieldGenerator : public SingleFieldGenerator {
+ public:
+ virtual ~ObjCObjFieldGenerator();
+
+ virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+ virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
+
+ protected:
+ explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator);
+};
+
+class RepeatedFieldGenerator : public ObjCObjFieldGenerator {
+ public:
+ virtual ~RepeatedFieldGenerator();
+
+ virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+ virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
+
+ virtual void GeneratePropertyImplementation(io::Printer* printer) const;
+
+ protected:
+ explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor);
+ virtual void FinishInitialization(void);
+ virtual bool WantsHasProperty(void) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedFieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+ explicit FieldGeneratorMap(const Descriptor* descriptor);
+ ~FieldGeneratorMap();
+
+ const FieldGenerator& get(const FieldDescriptor* field) const;
+ const FieldGenerator& get_extension(int index) const;
+
+ void SetOneofIndexBase(int index_base);
+
+ private:
+ const Descriptor* descriptor_;
+ scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+ scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
new file mode 100644
index 00000000..e60ae5a6
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -0,0 +1,371 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/objectivec/objectivec_file.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
+#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <sstream>
+
+namespace google {
+namespace protobuf {
+
+// This is also found in GPBBootstrap.h, and needs to be kept in sync. It
+// is the version check done to ensure generated code works with the current
+// runtime being used.
+const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30000;
+
+namespace compiler {
+namespace objectivec {
+
+FileGenerator::FileGenerator(const FileDescriptor *file)
+ : file_(file),
+ root_class_name_(FileClassName(file)),
+ is_public_dep_(false) {
+ // Validate the objc prefix.
+ ValidateObjCClassPrefix(file_);
+
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
+ enum_generators_.push_back(generator);
+ }
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ MessageGenerator *generator =
+ new MessageGenerator(root_class_name_, file_->message_type(i));
+ message_generators_.push_back(generator);
+ }
+ for (int i = 0; i < file_->extension_count(); i++) {
+ ExtensionGenerator *generator =
+ new ExtensionGenerator(root_class_name_, file_->extension(i));
+ extension_generators_.push_back(generator);
+ }
+}
+
+FileGenerator::~FileGenerator() {
+ STLDeleteContainerPointers(dependency_generators_.begin(),
+ dependency_generators_.end());
+ STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
+ STLDeleteContainerPointers(message_generators_.begin(),
+ message_generators_.end());
+ STLDeleteContainerPointers(extension_generators_.begin(),
+ extension_generators_.end());
+}
+
+void FileGenerator::GenerateHeader(io::Printer *printer) {
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", file_->name());
+
+ printer->Print(
+ "#import \"GPBProtocolBuffers.h\"\n"
+ "\n");
+
+ // Add some verification that the generated code matches the source the
+ // code is being compiled with.
+ printer->Print(
+ "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
+ "#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.\n"
+ "#endif\n"
+ "\n",
+ "protoc_gen_objc_version",
+ SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
+
+ const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
+ for (vector<FileGenerator *>::const_iterator iter =
+ dependency_generators.begin();
+ iter != dependency_generators.end(); ++iter) {
+ if ((*iter)->IsPublicDependency()) {
+ printer->Print("#import \"$header$.pbobjc.h\"\n",
+ "header", (*iter)->Path());
+ }
+ }
+
+ printer->Print(
+ "// @@protoc_insertion_point(imports)\n"
+ "\n"
+ "CF_EXTERN_C_BEGIN\n"
+ "\n");
+
+ set<string> fwd_decls;
+ for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ (*iter)->DetermineForwardDeclarations(&fwd_decls);
+ }
+ for (set<string>::const_iterator i(fwd_decls.begin());
+ i != fwd_decls.end(); ++i) {
+ printer->Print("$value$;\n", "value", *i);
+ }
+ if (fwd_decls.begin() != fwd_decls.end()) {
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ "NS_ASSUME_NONNULL_BEGIN\n"
+ "\n");
+
+ // need to write out all enums first
+ for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
+ iter != enum_generators_.end(); ++iter) {
+ (*iter)->GenerateHeader(printer);
+ }
+
+ for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ (*iter)->GenerateEnumHeader(printer);
+ }
+
+ // For extensions to chain together, the Root gets created even if there
+ // are no extensions.
+ printer->Print(
+ "#pragma mark - $root_class_name$\n"
+ "\n"
+ "@interface $root_class_name$ : GPBRootObject\n"
+ "\n"
+ "// The base class provides:\n"
+ "// + (GPBExtensionRegistry *)extensionRegistry;\n"
+ "// which is an GPBExtensionRegistry that includes all the extensions defined by\n"
+ "// this file and all files that it depends on.\n"
+ "\n"
+ "@end\n"
+ "\n",
+ "root_class_name", root_class_name_);
+
+ if (extension_generators_.size() > 0) {
+ // The dynamic methods block is only needed if there are extensions.
+ printer->Print(
+ "@interface $root_class_name$ (DynamicMethods)\n",
+ "root_class_name", root_class_name_);
+
+ for (vector<ExtensionGenerator *>::iterator iter =
+ extension_generators_.begin();
+ iter != extension_generators_.end(); ++iter) {
+ (*iter)->GenerateMembersHeader(printer);
+ }
+
+ printer->Print("@end\n\n");
+ } // extension_generators_.size() > 0
+
+ for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ (*iter)->GenerateMessageHeader(printer);
+ }
+
+ printer->Print(
+ "NS_ASSUME_NONNULL_END\n"
+ "\n"
+ "CF_EXTERN_C_END\n"
+ "\n"
+ "// @@protoc_insertion_point(global_scope)\n");
+}
+
+void FileGenerator::GenerateSource(io::Printer *printer) {
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", file_->name());
+
+ string header_file = Path() + ".pbobjc.h";
+ printer->Print(
+ "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n"
+ "#import \"$header_file$\"\n",
+ "header_file", header_file);
+ const vector<FileGenerator *> &dependency_generators =
+ DependencyGenerators();
+ for (vector<FileGenerator *>::const_iterator iter =
+ dependency_generators.begin();
+ iter != dependency_generators.end(); ++iter) {
+ if (!(*iter)->IsPublicDependency()) {
+ printer->Print("#import \"$header$.pbobjc.h\"\n",
+ "header", (*iter)->Path());
+ }
+ }
+ printer->Print(
+ "// @@protoc_insertion_point(imports)\n"
+ "\n");
+
+ printer->Print(
+ "#pragma mark - $root_class_name$\n"
+ "\n"
+ "@implementation $root_class_name$\n\n",
+ "root_class_name", root_class_name_);
+
+ // Generate the extension initialization structures for the top level and
+ // any nested messages.
+ ostringstream extensions_stringstream;
+ if (file_->extension_count() + file_->message_type_count() > 0) {
+ io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
+ io::Printer extensions_printer(&extensions_outputstream, '$');
+ for (vector<ExtensionGenerator *>::iterator iter =
+ extension_generators_.begin();
+ iter != extension_generators_.end(); ++iter) {
+ (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
+ }
+ for (vector<MessageGenerator *>::iterator iter =
+ message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
+ }
+ extensions_stringstream.flush();
+ }
+
+ // If there were any extensions or this file has any dependencies, output
+ // a registry to override to create the file specific registry.
+ const string& extensions_str = extensions_stringstream.str();
+ if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
+ printer->Print(
+ "+ (GPBExtensionRegistry*)extensionRegistry {\n"
+ " // This is called by +initialize so there is no need to worry\n"
+ " // about thread safety and initialization of registry.\n"
+ " static GPBExtensionRegistry* registry = nil;\n"
+ " if (!registry) {\n"
+ " GPBDebugCheckRuntimeVersion();\n"
+ " registry = [[GPBExtensionRegistry alloc] init];\n");
+
+ printer->Indent();
+ printer->Indent();
+
+ if (extensions_str.length() > 0) {
+ printer->Print(
+ "static GPBExtensionDescription descriptions[] = {\n");
+ printer->Indent();
+ printer->Print(extensions_str.c_str());
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
+ " GPBExtensionDescriptor *extension =\n"
+ " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]];\n"
+ " [registry addExtension:extension];\n"
+ " [self globallyRegisterExtension:extension];\n"
+ " [extension release];\n"
+ "}\n");
+ }
+
+ const vector<FileGenerator *> &dependency_generators =
+ DependencyGenerators();
+ for (vector<FileGenerator *>::const_iterator iter =
+ dependency_generators.begin();
+ iter != dependency_generators.end(); ++iter) {
+ printer->Print(
+ "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
+ "dependency", (*iter)->RootClassName());
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ " return registry;\n"
+ "}\n"
+ "\n");
+ }
+
+ printer->Print("@end\n\n");
+
+ // File descriptor only needed if there are messages to use it.
+ if (message_generators_.size() > 0) {
+ string syntax;
+ switch (file_->syntax()) {
+ case FileDescriptor::SYNTAX_UNKNOWN:
+ syntax = "GPBFileSyntaxUnknown";
+ break;
+ case FileDescriptor::SYNTAX_PROTO2:
+ syntax = "GPBFileSyntaxProto2";
+ break;
+ case FileDescriptor::SYNTAX_PROTO3:
+ syntax = "GPBFileSyntaxProto3";
+ break;
+ }
+ printer->Print(
+ "#pragma mark - $root_class_name$_FileDescriptor\n"
+ "\n"
+ "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
+ " // This is called by +initialize so there is no need to worry\n"
+ " // about thread safety of the singleton.\n"
+ " static GPBFileDescriptor *descriptor = NULL;\n"
+ " if (!descriptor) {\n"
+ " GPBDebugCheckRuntimeVersion();\n"
+ " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+ " syntax:$syntax$];\n"
+ " }\n"
+ " return descriptor;\n"
+ "}\n"
+ "\n",
+ "root_class_name", root_class_name_,
+ "package", file_->package(),
+ "syntax", syntax);
+ }
+
+ for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
+ iter != enum_generators_.end(); ++iter) {
+ (*iter)->GenerateSource(printer);
+ }
+ for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ (*iter)->GenerateSource(printer);
+ }
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(global_scope)\n");
+}
+
+const string FileGenerator::Path() const { return FilePath(file_); }
+
+const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
+ if (file_->dependency_count() != dependency_generators_.size()) {
+ set<string> public_import_names;
+ for (int i = 0; i < file_->public_dependency_count(); i++) {
+ public_import_names.insert(file_->public_dependency(i)->name());
+ }
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ FileGenerator *generator = new FileGenerator(file_->dependency(i));
+ const string& name = file_->dependency(i)->name();
+ bool public_import = (public_import_names.count(name) != 0);
+ generator->SetIsPublicDependency(public_import);
+ dependency_generators_.push_back(generator);
+ }
+ }
+ return dependency_generators_;
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
new file mode 100644
index 00000000..1bb4f0ea
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor; // descriptor.h
+namespace io {
+class Printer; // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumGenerator;
+class ExtensionGenerator;
+class MessageGenerator;
+
+class FileGenerator {
+ public:
+ explicit FileGenerator(const FileDescriptor* file);
+ ~FileGenerator();
+
+ void GenerateSource(io::Printer* printer);
+ void GenerateHeader(io::Printer* printer);
+
+ const string& RootClassName() const { return root_class_name_; }
+ const string Path() const;
+
+ bool IsPublicDependency() const { return is_public_dep_; }
+
+ protected:
+ void SetIsPublicDependency(bool is_public_dep) {
+ is_public_dep_ = is_public_dep;
+ }
+
+ private:
+ const FileDescriptor* file_;
+ string root_class_name_;
+
+ // Access this field through the DependencyGenerators accessor call below.
+ // Do not reference it directly.
+ vector<FileGenerator*> dependency_generators_;
+
+ vector<EnumGenerator*> enum_generators_;
+ vector<MessageGenerator*> message_generators_;
+ vector<ExtensionGenerator*> extension_generators_;
+ bool is_public_dep_;
+
+ const vector<FileGenerator*>& DependencyGenerators();
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
new file mode 100644
index 00000000..4449087a
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <iostream>
+#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
+#include <google/protobuf/compiler/objectivec/objectivec_file.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+ObjectiveCGenerator::ObjectiveCGenerator() {}
+
+ObjectiveCGenerator::~ObjectiveCGenerator() {}
+
+bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const {
+ // ObjC doesn't have any options at the moment, error if passed one.
+ vector<pair<string, string> > options;
+ ParseGeneratorParameter(parameter, &options);
+ for (int i = 0; i < options.size(); i++) {
+ *error = "error:: Unknown generator option: " + options[i].first;
+ return false;
+ }
+
+ FileGenerator file_generator(file);
+
+ string filepath = FilePath(file);
+
+ // Generate header.
+ {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(filepath + ".pbobjc.h"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateHeader(&printer);
+ }
+
+ // Generate m file.
+ {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(filepath + ".pbobjc.m"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateSource(&printer);
+ }
+
+ return true;
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
new file mode 100644
index 00000000..24286ac9
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
@@ -0,0 +1,60 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Generates ObjectiveC code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class LIBPROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator {
+ public:
+ ObjectiveCGenerator();
+ ~ObjectiveCGenerator();
+
+ // implements CodeGenerator ----------------------------------------
+ bool Generate(const FileDescriptor* file, const string& parameter,
+ OutputDirectory* output_directory, string* error) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator);
+};
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
new file mode 100644
index 00000000..45d122d1
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -0,0 +1,1045 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <climits>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+// error cases, so it seems to be ok to use as a back door for errors.
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+// islower()/isupper()/tolower()/toupper() change based on locale.
+//
+// src/google/protobuf/stubs/strutil.h:150 has the same pattern. For the
+// Objective C plugin, test failures were seen on TravisCI because isupper('A')
+// was coming back false for some server's locale. This approach avoids any
+// such issues.
+
+bool IsLower(const char c) {
+ return ('a' <= c && c <= 'z');
+}
+
+bool IsUpper(const char c) {
+ return ('A' <= c && c <= 'Z');
+}
+
+char ToLower(char c) {
+ if ('A' <= c && c <= 'Z') {
+ c += 'a' - 'A';
+ }
+ return c;
+}
+
+// toupper() changes based on locale. We don't want this!
+char ToUpper(char c) {
+ if ('a' <= c && c <= 'z') {
+ c += 'A' - 'a';
+ }
+ return c;
+}
+
+string TrimString(const string& s) {
+ string::size_type start = s.find_first_not_of(" \n\r\t");
+ if (start == string::npos) {
+ return "";
+ }
+ string::size_type end = s.find_last_not_of(" \n\r\t") + 1;
+ return s.substr(start, end - start);
+}
+
+hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) {
+ hash_set<string> result;
+ for (int i = 0; i < num_words; i++) {
+ result.insert(words[i]);
+ }
+ return result;
+}
+
+const char* const kUpperSegmentsList[] = {"url", "http", "https"};
+
+hash_set<string> kUpperSegments =
+ MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
+
+// Internal helper for name handing.
+// Do not expose this outside of helpers, stick to having functions for specific
+// cases (ClassName(), FieldName()), so there is always consistent suffix rules.
+string UnderscoresToCamelCase(const string& input, bool first_capitalized) {
+ vector<string> values;
+ string current;
+
+ bool last_char_was_number = false;
+ bool last_char_was_lower = false;
+ bool last_char_was_upper = false;
+ for (int i = 0; i < input.size(); i++) {
+ char c = input[i];
+ if (c >= '0' && c <= '9') {
+ if (!last_char_was_number) {
+ values.push_back(current);
+ current = "";
+ }
+ current += c;
+ last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+ last_char_was_number = true;
+ } else if (IsLower(c)) {
+ // lowercase letter can follow a lowercase or uppercase letter
+ if (!last_char_was_lower && !last_char_was_upper) {
+ values.push_back(current);
+ current = "";
+ }
+ current += c; // already lower
+ last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+ last_char_was_lower = true;
+ } else if (IsUpper(c)) {
+ if (!last_char_was_upper) {
+ values.push_back(current);
+ current = "";
+ }
+ current += ToLower(c);
+ last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+ last_char_was_upper = true;
+ } else {
+ last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+ }
+ }
+ values.push_back(current);
+
+ for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
+ string value = *i;
+ bool all_upper = (kUpperSegments.count(value) > 0);
+ for (int j = 0; j < value.length(); j++) {
+ if (j == 0 || all_upper) {
+ value[j] = ToUpper(value[j]);
+ } else {
+ // Nothing, already in lower.
+ }
+ }
+ *i = value;
+ }
+ string result;
+ for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
+ result += *i;
+ }
+ if ((result.length() != 0) && !first_capitalized) {
+ result[0] = ToLower(result[0]);
+ }
+ return result;
+}
+
+const char* const kReservedWordList[] = {
+ // Objective C "keywords" that aren't in C
+ // From
+ // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
+ "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
+ "self",
+
+ // C/C++ keywords (Incl C++ 0x11)
+ // From http://en.cppreference.com/w/cpp/keywords
+ "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor",
+ "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
+ "compl", "const", "constexpr", "const_cast", "continue", "decltype",
+ "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit",
+ "export", "extern ", "false", "float", "for", "friend", "goto", "if",
+ "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
+ "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected",
+ "public", "register", "reinterpret_cast", "return", "short", "signed",
+ "sizeof", "static", "static_assert", "static_cast", "struct", "switch",
+ "template", "this", "thread_local", "throw", "true", "try", "typedef",
+ "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
+ "volatile", "wchar_t", "while", "xor", "xor_eq",
+
+ // C99 keywords
+ // From
+ // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm
+ "restrict",
+
+ // Objective-C Runtime typedefs
+ // From <obc/runtime.h>
+ "Category", "Ivar", "Method", "Protocol",
+
+ // NSObject Methods
+ // new is covered by C++ keywords.
+ "description", "debugDescription", "finalize", "hash", "dealloc", "init",
+ "class", "superclass", "retain", "release", "autorelease", "retainCount",
+ "zone", "isProxy", "copy", "mutableCopy", "classForCoder",
+
+ // GPBMessage Methods
+ // Only need to add instance methods that may conflict with
+ // method declared in protos. The main cases are methods
+ // that take no arguments, or setFoo:/hasFoo: type methods.
+ "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
+ "extensionsCurrentlySet", "isInitialized", "serializedSize",
+ "sortedExtensionsInUse", "unknownFields",
+
+ // MacTypes.h names
+ "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
+ "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
+ "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
+ "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
+ "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
+};
+
+hash_set<string> kReservedWords =
+ MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
+
+string SanitizeNameForObjC(const string& input, const string& extension) {
+ if (kReservedWords.count(input) > 0) {
+ return input + extension;
+ }
+ return input;
+}
+
+string NameFromFieldDescriptor(const FieldDescriptor* field) {
+ if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ return field->message_type()->name();
+ } else {
+ return field->name();
+ }
+}
+
+// Escape C++ trigraphs by escaping question marks to \?
+string EscapeTrigraphs(const string& to_escape) {
+ return StringReplace(to_escape, "?", "\\?", true);
+}
+
+void PathSplit(const string& path, string* directory, string* basename) {
+ string::size_type last_slash = path.rfind('/');
+ if (last_slash == string::npos) {
+ if (directory) {
+ *directory = "";
+ }
+ if (basename) {
+ *basename = path;
+ }
+ } else {
+ if (directory) {
+ *directory = path.substr(0, last_slash);
+ }
+ if (basename) {
+ *basename = path.substr(last_slash + 1);
+ }
+ }
+}
+
+bool IsSpecialName(const string& name, const string* special_names,
+ size_t count) {
+ for (size_t i = 0; i < count; ++i) {
+ size_t length = special_names[i].length();
+ if (name.compare(0, length, special_names[i]) == 0) {
+ if (name.length() > length) {
+ // If name is longer than the retained_name[i] that it matches
+ // the next character must be not lower case (newton vs newTon vs
+ // new_ton).
+ return !IsLower(name[length]);
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+string StripProto(const string& filename) {
+ if (HasSuffixString(filename, ".protodevel")) {
+ return StripSuffixString(filename, ".protodevel");
+ } else {
+ return StripSuffixString(filename, ".proto");
+ }
+}
+
+bool IsRetainedName(const string& name) {
+ // List of prefixes from
+ // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
+ static const string retained_names[] = {"new", "alloc", "copy",
+ "mutableCopy"};
+ return IsSpecialName(name, retained_names,
+ sizeof(retained_names) / sizeof(retained_names[0]));
+}
+
+bool IsInitName(const string& name) {
+ static const string init_names[] = {"init"};
+ return IsSpecialName(name, init_names,
+ sizeof(init_names) / sizeof(init_names[0]));
+}
+
+string BaseFileName(const FileDescriptor* file) {
+ string basename;
+ PathSplit(file->name(), NULL, &basename);
+ return basename;
+}
+
+string FileName(const FileDescriptor* file) {
+ string path = FilePath(file);
+ string basename;
+ PathSplit(path, NULL, &basename);
+ return basename;
+}
+
+string FilePath(const FileDescriptor* file) {
+ string output;
+ string basename;
+ string directory;
+ PathSplit(file->name(), &directory, &basename);
+ if (directory.length() > 0) {
+ output = directory + "/";
+ }
+ basename = StripProto(basename);
+
+ // CamelCase to be more ObjC friendly.
+ basename = UnderscoresToCamelCase(basename, true);
+
+ output += basename;
+ return output;
+}
+
+string FileClassPrefix(const FileDescriptor* file) {
+ // Default is empty string, no need to check has_objc_class_prefix.
+ string result = file->options().objc_class_prefix();
+ return result;
+}
+
+void ValidateObjCClassPrefix(const FileDescriptor* file) {
+ string prefix = file->options().objc_class_prefix();
+ if (prefix.length() > 0) {
+ // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+ // error cases, so it seems to be ok to use as a back door for errors.
+ if (!IsUpper(prefix[0])) {
+ cerr << endl
+ << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+ << prefix << "\";' in '" << file->name() << "';"
+ << " it should start with a capital letter."
+ << endl;
+ cerr.flush();
+ }
+ if (prefix.length() < 3) {
+ cerr << endl
+ << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+ << prefix << "\";' in '" << file->name() << "';"
+ << " Apple recommends they should be at least 3 characters long."
+ << endl;
+ cerr.flush();
+ }
+ }
+}
+
+string FileClassName(const FileDescriptor* file) {
+ string name = FileClassPrefix(file);
+ name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
+ name += "Root";
+ // There aren't really any reserved words that end in "Root", but playing
+ // it safe and checking.
+ return SanitizeNameForObjC(name, "_RootClass");
+}
+
+string ClassNameWorker(const Descriptor* descriptor) {
+ string name;
+ if (descriptor->containing_type() != NULL) {
+ name = ClassNameWorker(descriptor->containing_type());
+ name += "_";
+ }
+ return name + descriptor->name();
+}
+
+string ClassNameWorker(const EnumDescriptor* descriptor) {
+ string name;
+ if (descriptor->containing_type() != NULL) {
+ name = ClassNameWorker(descriptor->containing_type());
+ name += "_";
+ }
+ return name + descriptor->name();
+}
+
+string ClassName(const Descriptor* descriptor) {
+ // 1. Message names are used as is (style calls for CamelCase, trust it).
+ // 2. Check for reserved word at the very end and then suffix things.
+ string prefix = FileClassPrefix(descriptor->file());
+ string name = ClassNameWorker(descriptor);
+ return SanitizeNameForObjC(prefix + name, "_Class");
+}
+
+string EnumName(const EnumDescriptor* descriptor) {
+ // 1. Enum names are used as is (style calls for CamelCase, trust it).
+ // 2. Check for reserved word at the every end and then suffix things.
+ // message Fixed {
+ // message Size {...}
+ // enum Mumble {...}
+ // ...
+ // }
+ // yields Fixed_Class, Fixed_Size.
+ string name = FileClassPrefix(descriptor->file());
+ name += ClassNameWorker(descriptor);
+ return SanitizeNameForObjC(name, "_Enum");
+}
+
+string EnumValueName(const EnumValueDescriptor* descriptor) {
+ // Because of the Switch enum compatibility, the name on the enum has to have
+ // the suffix handing, so it slightly diverges from how nested classes work.
+ // enum Fixed {
+ // FOO = 1
+ // }
+ // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo).
+ const string& class_name = EnumName(descriptor->type());
+ const string& value_str = UnderscoresToCamelCase(descriptor->name(), true);
+ const string& name = class_name + "_" + value_str;
+ // There aren't really any reserved words with an underscore and a leading
+ // capital letter, but playing it safe and checking.
+ return SanitizeNameForObjC(name, "_Value");
+}
+
+string EnumValueShortName(const EnumValueDescriptor* descriptor) {
+ // Enum value names (EnumValueName above) are the enum name turned into
+ // a class name and then the value name is CamelCased and concatenated; the
+ // whole thing then gets sanitized for reserved words.
+ // The "short name" is intended to be the final leaf, the value name; but
+ // you can't simply send that off to sanitize as that could result in it
+ // getting modified when the full name didn't. For example enum
+ // "StorageModes" has a value "retain". So the full name is
+ // "StorageModes_Retain", but if we sanitize "retain" it would become
+ // "RetainValue".
+ // So the right way to get the short name is to take the full enum name
+ // and then strip off the enum name (leaving the value name and anything
+ // done by sanitize).
+ const string& class_name = EnumName(descriptor->type());
+ const string& long_name_prefix = class_name + "_";
+ const string& long_name = EnumValueName(descriptor);
+ return StripPrefixString(long_name, long_name_prefix);
+}
+
+string UnCamelCaseEnumShortName(const string& name) {
+ string result;
+ for (int i = 0; i < name.size(); i++) {
+ char c = name[i];
+ if (i > 0 && c >= 'A' && c <= 'Z') {
+ result += '_';
+ }
+ result += ToUpper(c);
+ }
+ return result;
+}
+
+string ExtensionMethodName(const FieldDescriptor* descriptor) {
+ const string& name = NameFromFieldDescriptor(descriptor);
+ const string& result = UnderscoresToCamelCase(name, false);
+ return SanitizeNameForObjC(result, "_Extension");
+}
+
+string FieldName(const FieldDescriptor* field) {
+ const string& name = NameFromFieldDescriptor(field);
+ string result = UnderscoresToCamelCase(name, false);
+ if (field->is_repeated() && !field->is_map()) {
+ // Add "Array" before do check for reserved worlds.
+ result += "Array";
+ } else {
+ // If it wasn't repeated, but ends in "Array", force on the _p suffix.
+ if (HasSuffixString(result, "Array")) {
+ result += "_p";
+ }
+ }
+ return SanitizeNameForObjC(result, "_p");
+}
+
+string FieldNameCapitalized(const FieldDescriptor* field) {
+ // Want the same suffix handling, so upcase the first letter of the other
+ // name.
+ string result = FieldName(field);
+ if (result.length() > 0) {
+ result[0] = ToUpper(result[0]);
+ }
+ return result;
+}
+
+string OneofEnumName(const OneofDescriptor* descriptor) {
+ const Descriptor* fieldDescriptor = descriptor->containing_type();
+ string name = ClassName(fieldDescriptor);
+ name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase";
+ // No sanitize needed because the OS never has names that end in _OneOfCase.
+ return name;
+}
+
+string OneofName(const OneofDescriptor* descriptor) {
+ string name = UnderscoresToCamelCase(descriptor->name(), false);
+ // No sanitize needed because it gets OneOfCase added and that shouldn't
+ // ever conflict.
+ return name;
+}
+
+string OneofNameCapitalized(const OneofDescriptor* descriptor) {
+ // Use the common handling and then up-case the first letter.
+ string result = OneofName(descriptor);
+ if (result.length() > 0) {
+ result[0] = ToUpper(result[0]);
+ }
+ return result;
+}
+
+string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field) {
+ string worker(name);
+ if (HasSuffixString(worker, "_p")) {
+ worker = StripSuffixString(worker, "_p");
+ }
+ if (field->is_repeated() && HasSuffixString(worker, "Array")) {
+ worker = StripSuffixString(worker, "Array");
+ }
+ if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ if (worker.length() > 0) {
+ if (worker[0] >= 'a' && worker[0] <= 'z') {
+ worker[0] = ToUpper(worker[0]);
+ }
+ }
+ return worker;
+ } else {
+ string result;
+ for (int i = 0; i < worker.size(); i++) {
+ char c = worker[i];
+ if (c >= 'A' && c <= 'Z') {
+ if (i > 0) {
+ result += '_';
+ }
+ result += ToLower(c);
+ } else {
+ result += c;
+ }
+ }
+ return result;
+ }
+}
+
+string GetCapitalizedType(const FieldDescriptor* field) {
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_INT32:
+ return "Int32";
+ case FieldDescriptor::TYPE_UINT32:
+ return "UInt32";
+ case FieldDescriptor::TYPE_SINT32:
+ return "SInt32";
+ case FieldDescriptor::TYPE_FIXED32:
+ return "Fixed32";
+ case FieldDescriptor::TYPE_SFIXED32:
+ return "SFixed32";
+ case FieldDescriptor::TYPE_INT64:
+ return "Int64";
+ case FieldDescriptor::TYPE_UINT64:
+ return "UInt64";
+ case FieldDescriptor::TYPE_SINT64:
+ return "SInt64";
+ case FieldDescriptor::TYPE_FIXED64:
+ return "Fixed64";
+ case FieldDescriptor::TYPE_SFIXED64:
+ return "SFixed64";
+ case FieldDescriptor::TYPE_FLOAT:
+ return "Float";
+ case FieldDescriptor::TYPE_DOUBLE:
+ return "Double";
+ case FieldDescriptor::TYPE_BOOL:
+ return "Bool";
+ case FieldDescriptor::TYPE_STRING:
+ return "String";
+ case FieldDescriptor::TYPE_BYTES:
+ return "Bytes";
+ case FieldDescriptor::TYPE_ENUM:
+ return "Enum";
+ case FieldDescriptor::TYPE_GROUP:
+ return "Group";
+ case FieldDescriptor::TYPE_MESSAGE:
+ return "Message";
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
+ switch (field_type) {
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_SINT32:
+ case FieldDescriptor::TYPE_SFIXED32:
+ return OBJECTIVECTYPE_INT32;
+
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_FIXED32:
+ return OBJECTIVECTYPE_UINT32;
+
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_SINT64:
+ case FieldDescriptor::TYPE_SFIXED64:
+ return OBJECTIVECTYPE_INT64;
+
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_FIXED64:
+ return OBJECTIVECTYPE_UINT64;
+
+ case FieldDescriptor::TYPE_FLOAT:
+ return OBJECTIVECTYPE_FLOAT;
+
+ case FieldDescriptor::TYPE_DOUBLE:
+ return OBJECTIVECTYPE_DOUBLE;
+
+ case FieldDescriptor::TYPE_BOOL:
+ return OBJECTIVECTYPE_BOOLEAN;
+
+ case FieldDescriptor::TYPE_STRING:
+ return OBJECTIVECTYPE_STRING;
+
+ case FieldDescriptor::TYPE_BYTES:
+ return OBJECTIVECTYPE_DATA;
+
+ case FieldDescriptor::TYPE_ENUM:
+ return OBJECTIVECTYPE_ENUM;
+
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_MESSAGE:
+ return OBJECTIVECTYPE_MESSAGE;
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return OBJECTIVECTYPE_INT32;
+}
+
+bool IsPrimitiveType(const FieldDescriptor* field) {
+ ObjectiveCType type = GetObjectiveCType(field);
+ switch (type) {
+ case OBJECTIVECTYPE_INT32:
+ case OBJECTIVECTYPE_UINT32:
+ case OBJECTIVECTYPE_INT64:
+ case OBJECTIVECTYPE_UINT64:
+ case OBJECTIVECTYPE_FLOAT:
+ case OBJECTIVECTYPE_DOUBLE:
+ case OBJECTIVECTYPE_BOOLEAN:
+ case OBJECTIVECTYPE_ENUM:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+bool IsReferenceType(const FieldDescriptor* field) {
+ return !IsPrimitiveType(field);
+}
+
+static string HandleExtremeFloatingPoint(string val, bool add_float_suffix) {
+ if (val == "nan") {
+ return "NAN";
+ } else if (val == "inf") {
+ return "INFINITY";
+ } else if (val == "-inf") {
+ return "-INFINITY";
+ } else {
+ // float strings with ., e or E need to have f appended
+ if (add_float_suffix &&
+ (val.find(".") != string::npos || val.find("e") != string::npos ||
+ val.find("E") != string::npos)) {
+ val += "f";
+ }
+ return val;
+ }
+}
+
+string GPBGenericValueFieldName(const FieldDescriptor* field) {
+ // Returns the field within the GPBGenericValue union to use for the given
+ // field.
+ if (field->is_repeated()) {
+ return "valueMessage";
+ }
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return "valueInt32";
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return "valueUInt32";
+ case FieldDescriptor::CPPTYPE_INT64:
+ return "valueInt64";
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return "valueUInt64";
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return "valueFloat";
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return "valueDouble";
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return "valueBool";
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ return "valueData";
+ } else {
+ return "valueString";
+ }
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return "valueEnum";
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return "valueMessage";
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+
+string DefaultValue(const FieldDescriptor* field) {
+ // Repeated fields don't have defaults.
+ if (field->is_repeated()) {
+ return "nil";
+ }
+
+ // Switch on cpp_type since we need to know which default_value_* method
+ // of FieldDescriptor to call.
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ // gcc and llvm reject the decimal form of kint32min and kint64min.
+ if (field->default_value_int32() == INT_MIN) {
+ return "-0x80000000";
+ }
+ return SimpleItoa(field->default_value_int32());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return SimpleItoa(field->default_value_uint32()) + "U";
+ case FieldDescriptor::CPPTYPE_INT64:
+ // gcc and llvm reject the decimal form of kint32min and kint64min.
+ if (field->default_value_int64() == LLONG_MIN) {
+ return "-0x8000000000000000LL";
+ }
+ return SimpleItoa(field->default_value_int64()) + "LL";
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return SimpleItoa(field->default_value_uint64()) + "ULL";
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return HandleExtremeFloatingPoint(
+ SimpleDtoa(field->default_value_double()), false);
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return HandleExtremeFloatingPoint(
+ SimpleFtoa(field->default_value_float()), true);
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() ? "YES" : "NO";
+ case FieldDescriptor::CPPTYPE_STRING: {
+ const bool has_default_value = field->has_default_value();
+ const string& default_string = field->default_value_string();
+ if (!has_default_value || default_string.length() == 0) {
+ // If the field is defined as being the empty string,
+ // then we will just assign to nil, as the empty string is the
+ // default for both strings and data.
+ return "nil";
+ }
+ if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ // We want constant fields in our data structures so we can
+ // declare them as static. To achieve this we cheat and stuff
+ // a escaped c string (prefixed with a length) into the data
+ // field, and cast it to an (NSData*) so it will compile.
+ // The runtime library knows how to handle it.
+
+ // Must convert to a standard byte order for packing length into
+ // a cstring.
+ uint32 length = ghtonl(default_string.length());
+ string bytes((const char*)&length, sizeof(length));
+ bytes.append(default_string);
+ return "(NSData*)\"" + CEscape(bytes) + "\"";
+ } else {
+ return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\"";
+ }
+ }
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return EnumValueName(field->default_value_enum());
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return "nil";
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+string BuildFlagsString(const vector<string>& strings) {
+ if (strings.size() == 0) {
+ return "0";
+ }
+ string string;
+ for (size_t i = 0; i != strings.size(); ++i) {
+ if (i > 0) {
+ string.append(" | ");
+ }
+ string.append(strings[i]);
+ }
+ return string;
+}
+
+string BuildCommentsString(const SourceLocation& location) {
+ const string& comments = location.leading_comments.empty()
+ ? location.trailing_comments
+ : location.leading_comments;
+ vector<string> lines;
+ SplitStringAllowEmpty(comments, "\n", &lines);
+ while (!lines.empty() && lines.back().empty()) {
+ lines.pop_back();
+ }
+ string prefix("//");
+ string suffix("\n");
+ string final_comments;
+ for (int i = 0; i < lines.size(); i++) {
+ // We use $ for delimiters, so replace comments with dollars with
+ // html escaped version.
+ // None of the other compilers handle this (as of this writing) but we
+ // ran into it once, so just to be safe.
+ final_comments +=
+ prefix + StringReplace(lines[i], "$", "&#36;", true) + suffix;
+ }
+ return final_comments;
+}
+
+void TextFormatDecodeData::AddString(int32 key,
+ const string& input_for_decode,
+ const string& desired_output) {
+ for (vector<DataEntry>::const_iterator i = entries_.begin();
+ i != entries_.end(); ++i) {
+ if (i->first == key) {
+ cerr << "error: duplicate key (" << key
+ << ") making TextFormat data, input: \"" << input_for_decode
+ << "\", desired: \"" << desired_output << "\"." << endl;
+ cerr.flush();
+ abort();
+ }
+ }
+
+ const string& data = TextFormatDecodeData::DecodeDataForString(
+ input_for_decode, desired_output);
+ entries_.push_back(DataEntry(key, data));
+}
+
+string TextFormatDecodeData::Data() const {
+ ostringstream data_stringstream;
+
+ if (num_entries() > 0) {
+ io::OstreamOutputStream data_outputstream(&data_stringstream);
+ io::CodedOutputStream output_stream(&data_outputstream);
+
+ output_stream.WriteVarint32(num_entries());
+ for (vector<DataEntry>::const_iterator i = entries_.begin();
+ i != entries_.end(); ++i) {
+ output_stream.WriteVarint32(i->first);
+ output_stream.WriteString(i->second);
+ }
+ }
+
+ data_stringstream.flush();
+ return data_stringstream.str();
+}
+
+namespace {
+
+// Helper to build up the decode data for a string.
+class DecodeDataBuilder {
+ public:
+ DecodeDataBuilder() { Reset(); }
+
+ bool AddCharacter(const char desired, const char input);
+ void AddUnderscore() {
+ Push();
+ need_underscore_ = true;
+ }
+ string Finish() {
+ Push();
+ return decode_data_;
+ }
+
+ private:
+ static const uint8 kAddUnderscore = 0x80;
+
+ static const uint8 kOpAsIs = 0x00;
+ static const uint8 kOpFirstUpper = 0x40;
+ static const uint8 kOpFirstLower = 0x20;
+ static const uint8 kOpAllUpper = 0x60;
+
+ static const int kMaxSegmentLen = 0x1f;
+
+ void AddChar(const char desired) {
+ ++segment_len_;
+ is_all_upper_ &= IsUpper(desired);
+ }
+
+ void Push() {
+ uint8 op = (op_ | segment_len_);
+ if (need_underscore_) op |= kAddUnderscore;
+ if (op != 0) {
+ decode_data_ += (char)op;
+ }
+ Reset();
+ }
+
+ bool AddFirst(const char desired, const char input) {
+ if (desired == input) {
+ op_ = kOpAsIs;
+ } else if (desired == ToUpper(input)) {
+ op_ = kOpFirstUpper;
+ } else if (desired == ToLower(input)) {
+ op_ = kOpFirstLower;
+ } else {
+ // Can't be transformed to match.
+ return false;
+ }
+ AddChar(desired);
+ return true;
+ }
+
+ void Reset() {
+ need_underscore_ = false;
+ op_ = 0;
+ segment_len_ = 0;
+ is_all_upper_ = true;
+ }
+
+ bool need_underscore_;
+ bool is_all_upper_;
+ uint8 op_;
+ int segment_len_;
+
+ string decode_data_;
+};
+
+bool DecodeDataBuilder::AddCharacter(const char desired, const char input) {
+ // If we've hit the max size, push to start a new segment.
+ if (segment_len_ == kMaxSegmentLen) {
+ Push();
+ }
+ if (segment_len_ == 0) {
+ return AddFirst(desired, input);
+ }
+
+ // Desired and input match...
+ if (desired == input) {
+ // If we aren't transforming it, or we're upper casing it and it is
+ // supposed to be uppercase; just add it to the segment.
+ if ((op_ != kOpAllUpper) || IsUpper(desired)) {
+ AddChar(desired);
+ return true;
+ }
+
+ // Add the current segment, and start the next one.
+ Push();
+ return AddFirst(desired, input);
+ }
+
+ // If we need to uppercase, and everything so far has been uppercase,
+ // promote op to AllUpper.
+ if ((desired == ToUpper(input)) && is_all_upper_) {
+ op_ = kOpAllUpper;
+ AddChar(desired);
+ return true;
+ }
+
+ // Give up, push and start a new segment.
+ Push();
+ return AddFirst(desired, input);
+}
+
+// If decode data can't be generated, a directive for the raw string
+// is used instead.
+string DirectDecodeString(const string& str) {
+ string result;
+ result += (char)'\0'; // Marker for full string.
+ result += str;
+ result += (char)'\0'; // End of string.
+ return result;
+}
+
+} // namespace
+
+// static
+string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode,
+ const string& desired_output) {
+ if ((input_for_decode.size() == 0) || (desired_output.size() == 0)) {
+ cerr << "error: got empty string for making TextFormat data, input: \""
+ << input_for_decode << "\", desired: \"" << desired_output << "\"."
+ << endl;
+ cerr.flush();
+ abort();
+ }
+ if ((input_for_decode.find('\0') != string::npos) ||
+ (desired_output.find('\0') != string::npos)) {
+ cerr << "error: got a null char in a string for making TextFormat data,"
+ << " input: \"" << CEscape(input_for_decode) << "\", desired: \""
+ << CEscape(desired_output) << "\"." << endl;
+ cerr.flush();
+ abort();
+ }
+
+ DecodeDataBuilder builder;
+
+ // Walk the output building it from the input.
+ int x = 0;
+ for (int y = 0; y < desired_output.size(); y++) {
+ const char d = desired_output[y];
+ if (d == '_') {
+ builder.AddUnderscore();
+ continue;
+ }
+
+ if (x >= input_for_decode.size()) {
+ // Out of input, no way to encode it, just return a full decode.
+ return DirectDecodeString(desired_output);
+ }
+ if (builder.AddCharacter(d, input_for_decode[x])) {
+ ++x; // Consumed one input
+ } else {
+ // Couldn't transform for the next character, just return a full decode.
+ return DirectDecodeString(desired_output);
+ }
+ }
+
+ if (x != input_for_decode.size()) {
+ // Extra input (suffix from name sanitizing?), just return a full decode.
+ return DirectDecodeString(desired_output);
+ }
+
+ // Add the end marker.
+ return builder.Finish() + (char)'\0';
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
new file mode 100644
index 00000000..10d51a34
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -0,0 +1,173 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+string StripProto(const string& filename);
+
+// Returns true if the name requires a ns_returns_not_retained attribute applied
+// to it.
+bool IsRetainedName(const string& name);
+
+// Returns true if the name starts with "init" and will need to have special
+// handling under ARC.
+bool IsInitName(const string& name);
+
+// Gets the name of the file we're going to generate (sans the .pb.h
+// extension). This does not include the path to that file.
+string FileName(const FileDescriptor* file);
+
+// Gets the path of the file we're going to generate (sans the .pb.h
+// extension). The path will be dependent on the objectivec package
+// declared in the proto package.
+string FilePath(const FileDescriptor* file);
+
+// Checks the prefix for a given file and outputs any warnings/errors needed.
+void ValidateObjCClassPrefix(const FileDescriptor* file);
+
+// Gets the name of the root class we'll generate in the file. This class
+// is not meant for external consumption, but instead contains helpers that
+// the rest of the the classes need
+string FileClassName(const FileDescriptor* file);
+
+// These return the fully-qualified class name corresponding to the given
+// descriptor.
+string ClassName(const Descriptor* descriptor);
+string EnumName(const EnumDescriptor* descriptor);
+
+// Returns the fully-qualified name of the enum value corresponding to the
+// the descriptor.
+string EnumValueName(const EnumValueDescriptor* descriptor);
+
+// Returns the name of the enum value corresponding to the descriptor.
+string EnumValueShortName(const EnumValueDescriptor* descriptor);
+
+// Reverse what an enum does.
+string UnCamelCaseEnumShortName(const string& name);
+
+// Returns the name to use for the extension (used as the method off the file's
+// Root class).
+string ExtensionMethodName(const FieldDescriptor* descriptor);
+
+// Returns the transformed field name.
+string FieldName(const FieldDescriptor* field);
+string FieldNameCapitalized(const FieldDescriptor* field);
+
+// Returns the transformed oneof name.
+string OneofEnumName(const OneofDescriptor* descriptor);
+string OneofName(const OneofDescriptor* descriptor);
+string OneofNameCapitalized(const OneofDescriptor* descriptor);
+
+inline bool HasFieldPresence(const FileDescriptor* file) {
+ return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
+ return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+ return descriptor->options().map_entry();
+}
+
+// Reverse of the above.
+string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field);
+
+enum ObjectiveCType {
+ OBJECTIVECTYPE_INT32,
+ OBJECTIVECTYPE_UINT32,
+ OBJECTIVECTYPE_INT64,
+ OBJECTIVECTYPE_UINT64,
+ OBJECTIVECTYPE_FLOAT,
+ OBJECTIVECTYPE_DOUBLE,
+ OBJECTIVECTYPE_BOOLEAN,
+ OBJECTIVECTYPE_STRING,
+ OBJECTIVECTYPE_DATA,
+ OBJECTIVECTYPE_ENUM,
+ OBJECTIVECTYPE_MESSAGE
+};
+
+string GetCapitalizedType(const FieldDescriptor* field);
+
+ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type);
+
+inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
+ return GetObjectiveCType(field->type());
+}
+
+bool IsPrimitiveType(const FieldDescriptor* field);
+bool IsReferenceType(const FieldDescriptor* field);
+
+string GPBGenericValueFieldName(const FieldDescriptor* field);
+string DefaultValue(const FieldDescriptor* field);
+
+string BuildFlagsString(const vector<string>& strings);
+
+string BuildCommentsString(const SourceLocation& location);
+
+// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
+// the input into the the expected output.
+class LIBPROTOC_EXPORT TextFormatDecodeData {
+ public:
+ TextFormatDecodeData() {}
+
+ void AddString(int32 key, const string& input_for_decode,
+ const string& desired_output);
+ size_t num_entries() const { return entries_.size(); }
+ string Data() const;
+
+ static string DecodeDataForString(const string& input_for_decode,
+ const string& desired_output);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormatDecodeData);
+
+ typedef std::pair<int32, string> DataEntry;
+ vector<DataEntry> entries_;
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
new file mode 100644
index 00000000..dc1cef55
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
@@ -0,0 +1,257 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+namespace {
+
+TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_RawStrings) {
+ string input_for_decode("abcdefghIJ");
+ string desired_output_for_decode;
+ string expected;
+ string result;
+
+ // Different data, can't transform.
+
+ desired_output_for_decode = "zbcdefghIJ";
+ expected = string("\0zbcdefghIJ\0", 12);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+
+ desired_output_for_decode = "abcdezghIJ";
+ expected = string("\0abcdezghIJ\0", 12);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+
+ // Shortened data, can't transform.
+
+ desired_output_for_decode = "abcdefghI";
+ expected = string("\0abcdefghI\0", 11);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+
+ // Extra data, can't transform.
+
+ desired_output_for_decode = "abcdefghIJz";
+ expected = string("\0abcdefghIJz\0", 13);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+}
+
+TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_ByteCodes) {
+ string input_for_decode("abcdefghIJ");
+ string desired_output_for_decode;
+ string expected;
+ string result;
+
+ desired_output_for_decode = "abcdefghIJ";
+ expected = string("\x0A\x0", 2);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+
+ desired_output_for_decode = "_AbcdefghIJ";
+ expected = string("\xCA\x0", 2);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+
+ desired_output_for_decode = "ABCD__EfghI_j";
+ expected = string("\x64\x80\xC5\xA1\x0", 5);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+
+ // Long name so multiple decode ops are needed.
+
+ input_for_decode =
+ "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000";
+ desired_output_for_decode =
+ "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000";
+ expected = string("\x04\xA5\xA4\xA2\xBF\x1F\x0E\x84\x0", 9);
+ result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+ desired_output_for_decode);
+ EXPECT_EQ(expected, result);
+}
+
+// Death tests do not work on Windows as of yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(ObjCHelperDeathTest, TextFormatDecodeData_DecodeDataForString_Failures) {
+ // Empty inputs.
+
+ EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", ""),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got empty string for making TextFormat data, input:");
+ EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("a", ""),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got empty string for making TextFormat data, input:");
+ EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", "a"),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got empty string for making TextFormat data, input:");
+
+ // Null char in the string.
+
+ string str_with_null_char("ab\0c", 4);
+ EXPECT_EXIT(
+ TextFormatDecodeData::DecodeDataForString(str_with_null_char, "def"),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got a null char in a string for making TextFormat data, input:");
+ EXPECT_EXIT(
+ TextFormatDecodeData::DecodeDataForString("def", str_with_null_char),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got a null char in a string for making TextFormat data, input:");
+}
+#endif // PROTOBUF_HAS_DEATH_TEST
+
+TEST(ObjCHelper, TextFormatDecodeData_RawStrings) {
+ TextFormatDecodeData decode_data;
+
+ // Different data, can't transform.
+ decode_data.AddString(1, "abcdefghIJ", "zbcdefghIJ");
+ decode_data.AddString(3, "abcdefghIJ", "abcdezghIJ");
+ // Shortened data, can't transform.
+ decode_data.AddString(2, "abcdefghIJ", "abcdefghI");
+ // Extra data, can't transform.
+ decode_data.AddString(4, "abcdefghIJ", "abcdefghIJz");
+
+ EXPECT_EQ(4, decode_data.num_entries());
+
+ uint8 expected_data[] = {
+ 0x4,
+ 0x1, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0,
+ 0x3, 0x0, 'a', 'b', 'c', 'd', 'e', 'z', 'g', 'h', 'I', 'J', 0x0,
+ 0x2, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 0x0,
+ 0x4, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 'z', 0x0,
+ };
+ string expected((const char*)expected_data, sizeof(expected_data));
+
+ EXPECT_EQ(expected, decode_data.Data());
+}
+
+TEST(ObjCHelper, TextFormatDecodeData_ByteCodes) {
+ TextFormatDecodeData decode_data;
+
+ decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ");
+ decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ");
+ decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ");
+ decode_data.AddString(4, "abcdefghIJ", "ABCD__EfghI_j");
+ decode_data.AddString(1000,
+ "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000",
+ "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000");
+
+ EXPECT_EQ(5, decode_data.num_entries());
+
+ uint8 expected_data[] = {
+ 0x5,
+ // All as is (00 op)
+ 0x1, 0x0A, 0x0,
+ // Underscore, upper + 9 (10 op)
+ 0x3, 0xCA, 0x0,
+ // Upper + 3 (10 op), underscore, upper + 5 (10 op)
+ 0x2, 0x44, 0xC6, 0x0,
+ // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op),
+ // underscore, lower + 0 (01 op)
+ 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0,
+ // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op),
+ // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op),
+ // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00
+ // op),
+ // underscore, as is + 3 (00 op)
+ 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0,
+ };
+ string expected((const char*)expected_data, sizeof(expected_data));
+
+ EXPECT_EQ(expected, decode_data.Data());
+}
+
+
+// Death tests do not work on Windows as of yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(ObjCHelperDeathTest, TextFormatDecodeData_Failures) {
+ TextFormatDecodeData decode_data;
+
+ // Empty inputs.
+
+ EXPECT_EXIT(decode_data.AddString(1, "", ""),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got empty string for making TextFormat data, input:");
+ EXPECT_EXIT(decode_data.AddString(1, "a", ""),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got empty string for making TextFormat data, input:");
+ EXPECT_EXIT(decode_data.AddString(1, "", "a"),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got empty string for making TextFormat data, input:");
+
+ // Null char in the string.
+
+ string str_with_null_char("ab\0c", 4);
+ EXPECT_EXIT(
+ decode_data.AddString(1, str_with_null_char, "def"),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got a null char in a string for making TextFormat data, input:");
+ EXPECT_EXIT(
+ decode_data.AddString(1, "def", str_with_null_char),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: got a null char in a string for making TextFormat data, input:");
+
+ // Duplicate keys
+
+ decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ");
+ decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ");
+ decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ");
+ EXPECT_EXIT(decode_data.AddString(2, "xyz", "x_yz"),
+ ::testing::KilledBySignal(SIGABRT),
+ "error: duplicate key \\(2\\) making TextFormat data, input:");
+}
+#endif // PROTOBUF_HAS_DEATH_TEST
+
+// TODO(thomasvl): Should probably add some unittests for all the special cases
+// of name mangling (class name, field name, enum names). Rather than doing
+// this with an ObjC test in the objectivec directory, we should be able to
+// use src/google/protobuf/compiler/importer* (like other tests) to support a
+// virtual file system to feed in protos, once we have the Descriptor tree, the
+// tests could use the helper methods for generating names and validate the
+// right things are happening.
+
+} // namespace
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
new file mode 100644
index 00000000..2987f3db
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -0,0 +1,163 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+// MapFieldGenerator uses RepeatedFieldGenerator as the parent because it
+// provides a bunch of things (no has* methods, comments for contained type,
+// etc.).
+
+namespace {
+
+const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) {
+ ObjectiveCType type = GetObjectiveCType(descriptor);
+ switch (type) {
+ case OBJECTIVECTYPE_INT32:
+ return "Int32";
+ case OBJECTIVECTYPE_UINT32:
+ return "UInt32";
+ case OBJECTIVECTYPE_INT64:
+ return "Int64";
+ case OBJECTIVECTYPE_UINT64:
+ return "UInt64";
+ case OBJECTIVECTYPE_FLOAT:
+ return "Float";
+ case OBJECTIVECTYPE_DOUBLE:
+ return "Double";
+ case OBJECTIVECTYPE_BOOLEAN:
+ return "Bool";
+ case OBJECTIVECTYPE_STRING:
+ return (isKey ? "String" : "Object");
+ case OBJECTIVECTYPE_DATA:
+ return "Object";
+ case OBJECTIVECTYPE_ENUM:
+ return "Enum";
+ case OBJECTIVECTYPE_MESSAGE:
+ return "Object";
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+} // namespace
+
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor)
+ : RepeatedFieldGenerator(descriptor) {
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ value_field_generator_.reset(FieldGenerator::Make(value_descriptor));
+
+ // Pull over some variables_ from the value.
+ variables_["field_type"] = value_field_generator_->variable("field_type");
+ variables_["default"] = value_field_generator_->variable("default");
+ variables_["default_name"] = value_field_generator_->variable("default_name");
+
+ // Build custom field flags.
+ std::vector<string> field_flags;
+ field_flags.push_back("GPBFieldMapKey" + GetCapitalizedType(key_descriptor));
+ // Pull over the current text format custom name values that was calculated.
+ if (variables_["fieldflags"].find("GPBFieldTextFormatNameCustom") !=
+ string::npos) {
+ field_flags.push_back("GPBFieldTextFormatNameCustom");
+ }
+ // Pull over some info from the value's flags.
+ const string& value_field_flags =
+ value_field_generator_->variable("fieldflags");
+ if (value_field_flags.find("GPBFieldHasDefaultValue") != string::npos) {
+ field_flags.push_back("GPBFieldHasDefaultValue");
+ }
+ if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) {
+ field_flags.push_back("GPBFieldHasEnumDescriptor");
+ }
+ variables_["fieldflags"] = BuildFlagsString(field_flags);
+
+ ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
+ if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
+ ((value_objc_type == OBJECTIVECTYPE_STRING) ||
+ (value_objc_type == OBJECTIVECTYPE_DATA) ||
+ (value_objc_type == OBJECTIVECTYPE_MESSAGE))) {
+ variables_["array_storage_type"] = "NSMutableDictionary";
+ } else {
+ string base_name = MapEntryTypeName(key_descriptor, true);
+ base_name += MapEntryTypeName(value_descriptor, false);
+ base_name += "Dictionary";
+ variables_["array_storage_type"] = "GPB" + base_name;
+ }
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::FinishInitialization(void) {
+ RepeatedFieldGenerator::FinishInitialization();
+ // Use the array_comment suport in RepeatedFieldGenerator to output what the
+ // values in the map are.
+ const FieldDescriptor* value_descriptor =
+ descriptor_->message_type()->FindFieldByName("value");
+ ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
+ if ((value_objc_type == OBJECTIVECTYPE_MESSAGE) ||
+ (value_objc_type == OBJECTIVECTYPE_DATA) ||
+ (value_objc_type == OBJECTIVECTYPE_STRING) ||
+ (value_objc_type == OBJECTIVECTYPE_ENUM)) {
+ variables_["array_comment"] =
+ "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
+ } else {
+ variables_["array_comment"] = "";
+ }
+}
+
+void MapFieldGenerator::GenerateFieldDescriptionTypeSpecific(
+ io::Printer* printer) const {
+ // Relay it to the value generator to provide enum validator, message
+ // class, etc.
+ value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer);
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
new file mode 100644
index 00000000..173541f2
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class MapFieldGenerator : public RepeatedFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ public:
+ virtual void FinishInitialization(void);
+ virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+
+ protected:
+ explicit MapFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~MapFieldGenerator();
+
+ private:
+ scoped_ptr<FieldGenerator> value_field_generator_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
new file mode 100644
index 00000000..32671d42
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -0,0 +1,647 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
+#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+struct FieldOrderingByNumber {
+ inline bool operator()(const FieldDescriptor* a,
+ const FieldDescriptor* b) const {
+ return a->number() < b->number();
+ }
+};
+
+int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
+ // The first item in the object structure is our uint32[] for has bits.
+ // We then want to order things to make the instances as small as
+ // possible. So we follow the has bits with:
+ // 1. Bools (1 byte)
+ // 2. Anything always 4 bytes - float, *32, enums
+ // 3. Anything that is always a pointer (they will be 8 bytes on 64 bit
+ // builds and 4 bytes on 32bit builds.
+ // 4. Anything always 8 bytes - double, *64
+ //
+ // Why? Using 64bit builds as an example, this means worse case, we have
+ // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes
+ // are wasted before the 4 byte values. Then if we have an odd number of
+ // those 4 byte values, the 8 byte values will be pushed down by 32bits to
+ // keep them aligned. But the structure will end 8 byte aligned, so no
+ // waste on the end. If you did the reverse order, you could waste 4 bytes
+ // before the first 8 byte value (after the has array), then a single
+ // bool on the end would need 7 bytes of padding to make the overall
+ // structure 8 byte aligned; so 11 bytes, wasted total.
+
+ // Anything repeated is a GPB*Array/NSArray, so pointer.
+ if (descriptor->is_repeated()) {
+ return 3;
+ }
+
+ switch (descriptor->type()) {
+ // All always 8 bytes.
+ case FieldDescriptor::TYPE_DOUBLE:
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_SINT64:
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_SFIXED64:
+ case FieldDescriptor::TYPE_FIXED64:
+ return 4;
+
+ // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes
+ // depending on the build architecture.
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES:
+ return 3;
+
+ // All always 4 bytes (enums are int32s).
+ case FieldDescriptor::TYPE_FLOAT:
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_SINT32:
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_SFIXED32:
+ case FieldDescriptor::TYPE_FIXED32:
+ case FieldDescriptor::TYPE_ENUM:
+ return 2;
+
+ // 1 byte.
+ case FieldDescriptor::TYPE_BOOL:
+ return 1;
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return 0;
+}
+
+struct FieldOrderingByStorageSize {
+ inline bool operator()(const FieldDescriptor* a,
+ const FieldDescriptor* b) const {
+ // Order by grouping.
+ const int order_group_a = OrderGroupForFieldDescriptor(a);
+ const int order_group_b = OrderGroupForFieldDescriptor(b);
+ if (order_group_a != order_group_b) {
+ return order_group_a < order_group_b;
+ }
+ // Within the group, order by field number (provides stable ordering).
+ return a->number() < b->number();
+ }
+};
+
+struct ExtensionRangeOrdering {
+ bool operator()(const Descriptor::ExtensionRange* a,
+ const Descriptor::ExtensionRange* b) const {
+ return a->start < b->start;
+ }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+ const FieldDescriptor** fields =
+ new const FieldDescriptor* [descriptor->field_count()];
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields[i] = descriptor->field(i);
+ }
+ sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber());
+ return fields;
+}
+
+// Sort the fields of the given Descriptor by storage size into a new[]'d
+// array and return it.
+const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) {
+ const FieldDescriptor** fields =
+ new const FieldDescriptor* [descriptor->field_count()];
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields[i] = descriptor->field(i);
+ }
+ sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByStorageSize());
+ return fields;
+}
+} // namespace
+
+MessageGenerator::MessageGenerator(const string& root_classname,
+ const Descriptor* descriptor)
+ : root_classname_(root_classname),
+ descriptor_(descriptor),
+ field_generators_(descriptor),
+ class_name_(ClassName(descriptor_)) {
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ extension_generators_.push_back(
+ new ExtensionGenerator(class_name_, descriptor_->extension(i)));
+ }
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
+ oneof_generators_.push_back(generator);
+ }
+
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i));
+ enum_generators_.push_back(generator);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ MessageGenerator* generator =
+ new MessageGenerator(root_classname_, descriptor_->nested_type(i));
+ nested_message_generators_.push_back(generator);
+ }
+}
+
+MessageGenerator::~MessageGenerator() {
+ STLDeleteContainerPointers(extension_generators_.begin(),
+ extension_generators_.end());
+ STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
+ STLDeleteContainerPointers(nested_message_generators_.begin(),
+ nested_message_generators_.end());
+ STLDeleteContainerPointers(oneof_generators_.begin(),
+ oneof_generators_.end());
+}
+
+void MessageGenerator::GenerateStaticVariablesInitialization(
+ io::Printer* printer) {
+ for (vector<ExtensionGenerator*>::iterator iter =
+ extension_generators_.begin();
+ iter != extension_generators_.end(); ++iter) {
+ (*iter)->GenerateStaticVariablesInitialization(printer);
+ }
+
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->GenerateStaticVariablesInitialization(printer);
+ }
+}
+
+void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) {
+ if (!IsMapEntryMessage(descriptor_)) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+ // If it is a the field is repeated, the type will be and *Array, and we
+ // don't need any forward decl.
+ if (fieldDescriptor->is_repeated()) {
+ continue;
+ }
+ field_generators_.get(fieldDescriptor)
+ .DetermineForwardDeclarations(fwd_decls);
+ }
+ }
+
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->DetermineForwardDeclarations(fwd_decls);
+ }
+}
+
+void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
+ for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
+ iter != enum_generators_.end(); ++iter) {
+ (*iter)->GenerateHeader(printer);
+ }
+
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->GenerateEnumHeader(printer);
+ }
+}
+
+void MessageGenerator::GenerateExtensionRegistrationSource(
+ io::Printer* printer) {
+ for (vector<ExtensionGenerator*>::iterator iter =
+ extension_generators_.begin();
+ iter != extension_generators_.end(); ++iter) {
+ (*iter)->GenerateRegistrationSource(printer);
+ }
+
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->GenerateExtensionRegistrationSource(printer);
+ }
+}
+
+void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
+ // This a a map entry message, just recurse and do nothing directly.
+ if (IsMapEntryMessage(descriptor_)) {
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->GenerateMessageHeader(printer);
+ }
+ return;
+ }
+
+ printer->Print(
+ "#pragma mark - $classname$\n"
+ "\n",
+ "classname", class_name_);
+
+ if (descriptor_->field_count()) {
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n",
+ "classname", class_name_);
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(sorted_fields[i])
+ .GenerateFieldNumberConstant(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("};\n\n");
+ }
+
+ for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+ iter != oneof_generators_.end(); ++iter) {
+ (*iter)->GenerateCaseEnum(printer);
+ }
+
+ string message_comments;
+ SourceLocation location;
+ if (descriptor_->GetSourceLocation(&location)) {
+ message_comments = BuildCommentsString(location);
+ } else {
+ message_comments = "";
+ }
+
+ printer->Print(
+ "$comments$@interface $classname$ : GPBMessage\n\n",
+ "classname", class_name_,
+ "comments", message_comments);
+
+ vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0);
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->containing_oneof() != NULL) {
+ const int oneof_index = field->containing_oneof()->index();
+ if (!seen_oneofs[oneof_index]) {
+ seen_oneofs[oneof_index] = 1;
+ oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration(
+ printer);
+ }
+ }
+ field_generators_.get(field).GeneratePropertyDeclaration(printer);
+ }
+
+ printer->Print("@end\n\n");
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateCFunctionDeclarations(printer);
+ }
+
+ if (!oneof_generators_.empty()) {
+ for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+ iter != oneof_generators_.end(); ++iter) {
+ (*iter)->GenerateClearFunctionDeclaration(printer);
+ }
+ printer->Print("\n");
+ }
+
+ if (descriptor_->extension_count() > 0) {
+ printer->Print("@interface $classname$ (DynamicMethods)\n\n",
+ "classname", class_name_);
+ for (vector<ExtensionGenerator*>::iterator iter =
+ extension_generators_.begin();
+ iter != extension_generators_.end(); ++iter) {
+ (*iter)->GenerateMembersHeader(printer);
+ }
+ printer->Print("@end\n\n");
+ }
+
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->GenerateMessageHeader(printer);
+ }
+}
+
+void MessageGenerator::GenerateSource(io::Printer* printer) {
+ if (!IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "#pragma mark - $classname$\n"
+ "\n",
+ "classname", class_name_);
+
+ printer->Print("@implementation $classname$\n\n",
+ "classname", class_name_);
+
+ for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+ iter != oneof_generators_.end(); ++iter) {
+ (*iter)->GeneratePropertyImplementation(printer);
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GeneratePropertyImplementation(printer);
+ }
+
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+ scoped_array<const FieldDescriptor*> size_order_fields(
+ SortFieldsByStorageSize(descriptor_));
+
+ vector<const Descriptor::ExtensionRange*> sorted_extensions;
+ for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+ sorted_extensions.push_back(descriptor_->extension_range(i));
+ }
+
+ sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeOrdering());
+
+ // TODO(thomasvl): Finish optimizing has bit. The current behavior is as
+ // follows:
+ // 1. objectivec_field.cc's SetCommonFieldVariables() defaults the has_index
+ // to the field's index in the list of fields.
+ // 2. RepeatedFieldGenerator::RepeatedFieldGenerator() sets has_index to
+ // GPBNoHasBit because repeated fields & map<> fields don't use the has
+ // bit.
+ // 3. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
+ // index that groups all the elements on of the oneof.
+ // So in has_storage, we need enough bits for the single fields that aren't
+ // in any oneof, and then one int32 for each oneof (to store the field
+ // number). So we could save a little space by not using the field's index
+ // and instead make a second pass only assigning indexes for the fields
+ // that would need it. The only savings would come when messages have over
+ // a multiple of 32 fields with some number being repeated or in oneofs to
+ // drop the count below that 32 multiple; so it hasn't seemed worth doing
+ // at the moment.
+ size_t num_has_bits = descriptor_->field_count();
+ size_t sizeof_has_storage = (num_has_bits + 31) / 32;
+ // Tell all the fields the oneof base.
+ for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+ iter != oneof_generators_.end(); ++iter) {
+ (*iter)->SetOneofIndexBase(sizeof_has_storage);
+ }
+ field_generators_.SetOneofIndexBase(sizeof_has_storage);
+ // Add an int32 for each oneof to store which is set.
+ sizeof_has_storage += descriptor_->oneof_decl_count();
+
+ printer->Print(
+ "\n"
+ "typedef struct $classname$__storage_ {\n"
+ " uint32_t _has_storage_[$sizeof_has_storage$];\n",
+ "classname", class_name_,
+ "sizeof_has_storage", SimpleItoa(sizeof_has_storage));
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(size_order_fields[i])
+ .GenerateFieldStorageDeclaration(printer);
+ }
+ printer->Outdent();
+
+ printer->Print("} $classname$__storage_;\n\n", "classname", class_name_);
+
+
+ printer->Print(
+ "// This method is threadsafe because it is initially called\n"
+ "// in +initialize for each subclass.\n"
+ "+ (GPBDescriptor *)descriptor {\n"
+ " static GPBDescriptor *descriptor = nil;\n"
+ " if (!descriptor) {\n");
+
+ bool has_oneofs = oneof_generators_.size();
+ if (has_oneofs) {
+ printer->Print(
+ " static GPBMessageOneofDescription oneofs[] = {\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+ iter != oneof_generators_.end(); ++iter) {
+ (*iter)->GenerateDescription(printer);
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " };\n");
+ }
+
+ TextFormatDecodeData text_format_decode_data;
+ bool has_fields = descriptor_->field_count() > 0;
+ if (has_fields) {
+ // TODO(thomasvl): The plugin's FieldGenerator::GenerateFieldDescription()
+ // wraps the fieldOptions's value of this structure in an CPP gate so
+ // they can be compiled away; but that still results in a const char* in
+ // the structure for a NULL pointer for every message field. If the
+ // fieldOptions are moved to a separate payload like the TextFormat extra
+ // data is, then it would shrink that static data shrinking the binaries
+ // a little more.
+ // TODO(thomasvl): proto3 syntax doens't need a defaultValue in the
+ // structure because primitive types are always zero. If we add a second
+ // structure and a different initializer, we can avoid the wasted static
+ // storage for every field in a proto3 message.
+ printer->Print(
+ " static GPBMessageFieldDescription fields[] = {\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); ++i) {
+ const FieldGenerator& field_generator =
+ field_generators_.get(sorted_fields[i]);
+ field_generator.GenerateFieldDescription(printer);
+ if (field_generator.needs_textformat_name_support()) {
+ text_format_decode_data.AddString(sorted_fields[i]->number(),
+ field_generator.generated_objc_name(),
+ field_generator.raw_field_name());
+ }
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " };\n");
+ }
+
+ bool has_enums = enum_generators_.size();
+ if (has_enums) {
+ printer->Print(
+ " static GPBMessageEnumDescription enums[] = {\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
+ iter != enum_generators_.end(); ++iter) {
+ printer->Print("{ .enumDescriptorFunc = $name$_EnumDescriptor },\n",
+ "name", (*iter)->name());
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " };\n");
+ }
+
+ bool has_extensions = sorted_extensions.size();
+ if (has_extensions) {
+ printer->Print(
+ " static GPBExtensionRange ranges[] = {\n");
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < sorted_extensions.size(); i++) {
+ printer->Print("{ .start = $start$, .end = $end$ },\n",
+ "start", SimpleItoa(sorted_extensions[i]->start),
+ "end", SimpleItoa(sorted_extensions[i]->end));
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " };\n");
+ }
+
+ map<string, string> vars;
+ vars["classname"] = class_name_;
+ vars["rootclassname"] = root_classname_;
+ vars["fields"] = has_fields ? "fields" : "NULL";
+ vars["fields_count"] =
+ has_fields ? "sizeof(fields) / sizeof(GPBMessageFieldDescription)" : "0";
+ vars["oneofs"] = has_oneofs ? "oneofs" : "NULL";
+ vars["oneof_count"] =
+ has_oneofs ? "sizeof(oneofs) / sizeof(GPBMessageOneofDescription)" : "0";
+ vars["enums"] = has_enums ? "enums" : "NULL";
+ vars["enum_count"] =
+ has_enums ? "sizeof(enums) / sizeof(GPBMessageEnumDescription)" : "0";
+ vars["ranges"] = has_extensions ? "ranges" : "NULL";
+ vars["range_count"] =
+ has_extensions ? "sizeof(ranges) / sizeof(GPBExtensionRange)" : "0";
+ vars["wireformat"] =
+ descriptor_->options().message_set_wire_format() ? "YES" : "NO";
+
+ if (text_format_decode_data.num_entries() == 0) {
+ printer->Print(
+ vars,
+ " GPBDescriptor *localDescriptor =\n"
+ " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
+ " rootClass:[$rootclassname$ class]\n"
+ " file:$rootclassname$_FileDescriptor()\n"
+ " fields:$fields$\n"
+ " fieldCount:$fields_count$\n"
+ " oneofs:$oneofs$\n"
+ " oneofCount:$oneof_count$\n"
+ " enums:$enums$\n"
+ " enumCount:$enum_count$\n"
+ " ranges:$ranges$\n"
+ " rangeCount:$range_count$\n"
+ " storageSize:sizeof($classname$__storage_)\n"
+ " wireFormat:$wireformat$];\n");
+ } else {
+ vars["extraTextFormatInfo"] = CEscape(text_format_decode_data.Data());
+ printer->Print(
+ vars,
+ "#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
+ " const char *extraTextFormatInfo = NULL;\n"
+ "#else\n"
+ " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
+ "#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
+ " GPBDescriptor *localDescriptor =\n"
+ " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
+ " rootClass:[$rootclassname$ class]\n"
+ " file:$rootclassname$_FileDescriptor()\n"
+ " fields:$fields$\n"
+ " fieldCount:$fields_count$\n"
+ " oneofs:$oneofs$\n"
+ " oneofCount:$oneof_count$\n"
+ " enums:$enums$\n"
+ " enumCount:$enum_count$\n"
+ " ranges:$ranges$\n"
+ " rangeCount:$range_count$\n"
+ " storageSize:sizeof($classname$__storage_)\n"
+ " wireFormat:$wireformat$\n"
+ " extraTextFormatInfo:extraTextFormatInfo];\n");
+ }
+ printer->Print(
+ " NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
+ " descriptor = localDescriptor;\n"
+ " }\n"
+ " return descriptor;\n"
+ "}\n\n"
+ "@end\n\n");
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateCFunctionImplementations(printer);
+ }
+
+ for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+ iter != oneof_generators_.end(); ++iter) {
+ (*iter)->GenerateClearFunctionImplementation(printer);
+ }
+ }
+
+ for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
+ iter != enum_generators_.end(); ++iter) {
+ (*iter)->GenerateSource(printer);
+ }
+
+ for (vector<MessageGenerator*>::iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ (*iter)->GenerateSource(printer);
+ }
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h
new file mode 100644
index 00000000..06b536ff
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h
@@ -0,0 +1,94 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_oneof.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class Printer; // printer.h
+} // namespace io
+
+namespace compiler {
+namespace objectivec {
+
+class ExtensionGenerator;
+class EnumGenerator;
+
+class MessageGenerator {
+ public:
+ MessageGenerator(const string& root_classname, const Descriptor* descriptor);
+ ~MessageGenerator();
+
+ void GenerateStaticVariablesInitialization(io::Printer* printer);
+ void GenerateEnumHeader(io::Printer* printer);
+ void GenerateMessageHeader(io::Printer* printer);
+ void GenerateSource(io::Printer* printer);
+ void GenerateExtensionRegistrationSource(io::Printer* printer);
+ void DetermineForwardDeclarations(set<string>* fwd_decls);
+
+ private:
+ void GenerateParseFromMethodsHeader(io::Printer* printer);
+
+ void GenerateSerializeOneFieldSource(io::Printer* printer,
+ const FieldDescriptor* field);
+ void GenerateSerializeOneExtensionRangeSource(
+ io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+ void GenerateMessageDescriptionSource(io::Printer* printer);
+ void GenerateDescriptionOneFieldSource(io::Printer* printer,
+ const FieldDescriptor* field);
+
+ const string root_classname_;
+ const Descriptor* descriptor_;
+ FieldGeneratorMap field_generators_;
+ const string class_name_;
+ vector<ExtensionGenerator*> extension_generators_;
+ vector<EnumGenerator*> enum_generators_;
+ vector<MessageGenerator*> nested_message_generators_;
+ vector<OneofGenerator*> oneof_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
new file mode 100644
index 00000000..f2ce4e5b
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ const string& message_type = ClassName(descriptor->message_type());
+ (*variables)["type"] = message_type;
+ (*variables)["containing_class"] = ClassName(descriptor->containing_type());
+ (*variables)["storage_type"] = message_type;
+ (*variables)["group_or_message"] =
+ (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message";
+
+ (*variables)["dataTypeSpecific_value"] = "GPBStringifySymbol(" + message_type + ")";
+}
+
+} // namespace
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor)
+ : ObjCObjFieldGenerator(descriptor) {
+ SetMessageVariables(descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::DetermineForwardDeclarations(
+ set<string>* fwd_decls) const {
+ // Class name is already in "storage_type".
+ fwd_decls->insert("@class " + variable("storage_type"));
+}
+
+bool MessageFieldGenerator::WantsHasProperty(void) const {
+ if (descriptor_->containing_oneof() != NULL) {
+ // If in a oneof, it uses the oneofcase instead of a has bit.
+ return false;
+ }
+ // In both proto2 & proto3, message fields have a has* property to tell
+ // when it is a non default value.
+ return true;
+}
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : RepeatedFieldGenerator(descriptor) {
+ SetMessageVariables(descriptor, &variables_);
+ variables_["array_storage_type"] = "NSMutableArray";
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
new file mode 100644
index 00000000..708ea566
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
@@ -0,0 +1,74 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class MessageFieldGenerator : public ObjCObjFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+ explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~MessageFieldGenerator();
+ virtual bool WantsHasProperty(void) const;
+
+ public:
+ virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~RepeatedMessageFieldGenerator();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
new file mode 100644
index 00000000..3cb87482
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
@@ -0,0 +1,138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_oneof.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+OneofGenerator::OneofGenerator(const OneofDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ variables_["enum_name"] = OneofEnumName(descriptor_);
+ variables_["name"] = OneofName(descriptor_);
+ variables_["capitalized_name"] = OneofNameCapitalized(descriptor_);
+ variables_["raw_index"] = SimpleItoa(descriptor_->index());
+ const Descriptor* msg_descriptor = descriptor_->containing_type();
+ variables_["owning_message_class"] = ClassName(msg_descriptor);
+
+ string comments;
+ SourceLocation location;
+ if (descriptor_->GetSourceLocation(&location)) {
+ comments = BuildCommentsString(location);
+ } else {
+ comments = "";
+ }
+ variables_["comments"] = comments;
+}
+
+OneofGenerator::~OneofGenerator() {}
+
+void OneofGenerator::SetOneofIndexBase(int index_base) {
+ int index = descriptor_->index() + index_base;
+ // Flip the sign to mark it as a oneof.
+ variables_["index"] = SimpleItoa(-index);
+}
+
+void OneofGenerator::GenerateCaseEnum(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "typedef GPB_ENUM($enum_name$) {\n");
+ printer->Indent();
+ printer->Print(
+ variables_,
+ "$enum_name$_GPBUnsetOneOfCase = 0,\n");
+ string enum_name = variables_["enum_name"];
+ for (int j = 0; j < descriptor_->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->field(j);
+ string field_name = FieldNameCapitalized(field);
+ printer->Print(
+ "$enum_name$_$field_name$ = $field_number$,\n",
+ "enum_name", enum_name,
+ "field_name", field_name,
+ "field_number", SimpleItoa(field->number()));
+ }
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+}
+
+void OneofGenerator::GeneratePublicCasePropertyDeclaration(
+ io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "$comments$"
+ "@property(nonatomic, readonly) $enum_name$ $name$OneOfCase;\n"
+ "\n");
+}
+
+void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n");
+}
+
+void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "@dynamic $name$OneOfCase;\n");
+}
+
+void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n"
+ " GPBDescriptor *descriptor = [message descriptor];\n"
+ " GPBOneofDescriptor *oneof = descriptor->oneofs_[$raw_index$];\n"
+ " GPBMaybeClearOneof(message, oneof, 0);\n"
+ "}\n");
+}
+
+void OneofGenerator::GenerateDescription(io::Printer* printer) {
+ printer->Print(
+ variables_,
+ "{\n"
+ " .name = \"$name$\",\n"
+ " .index = $index$,\n"
+ "},\n");
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
new file mode 100644
index 00000000..bcba82da
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
@@ -0,0 +1,77 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer; // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class OneofGenerator {
+ public:
+ explicit OneofGenerator(const OneofDescriptor* descriptor);
+ ~OneofGenerator();
+
+ void SetOneofIndexBase(int index_base);
+
+ void GenerateCaseEnum(io::Printer* printer);
+
+ void GeneratePublicCasePropertyDeclaration(io::Printer* printer);
+ void GenerateClearFunctionDeclaration(io::Printer* printer);
+
+ void GeneratePropertyImplementation(io::Printer* printer);
+ void GenerateClearFunctionImplementation(io::Printer* printer);
+ void GenerateDescription(io::Printer* printer);
+
+ private:
+ const OneofDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
new file mode 100644
index 00000000..c185b66d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
@@ -0,0 +1,171 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* PrimitiveTypeName(const FieldDescriptor* descriptor) {
+ ObjectiveCType type = GetObjectiveCType(descriptor);
+ switch (type) {
+ case OBJECTIVECTYPE_INT32:
+ return "int32_t";
+ case OBJECTIVECTYPE_UINT32:
+ return "uint32_t";
+ case OBJECTIVECTYPE_INT64:
+ return "int64_t";
+ case OBJECTIVECTYPE_UINT64:
+ return "uint64_t";
+ case OBJECTIVECTYPE_FLOAT:
+ return "float";
+ case OBJECTIVECTYPE_DOUBLE:
+ return "double";
+ case OBJECTIVECTYPE_BOOLEAN:
+ return "BOOL";
+ case OBJECTIVECTYPE_STRING:
+ return "NSString";
+ case OBJECTIVECTYPE_DATA:
+ return "NSData";
+ case OBJECTIVECTYPE_ENUM:
+ return "int32_t";
+ case OBJECTIVECTYPE_MESSAGE:
+ return NULL;
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) {
+ ObjectiveCType type = GetObjectiveCType(descriptor);
+ switch (type) {
+ case OBJECTIVECTYPE_INT32:
+ return "Int32";
+ case OBJECTIVECTYPE_UINT32:
+ return "UInt32";
+ case OBJECTIVECTYPE_INT64:
+ return "Int64";
+ case OBJECTIVECTYPE_UINT64:
+ return "UInt64";
+ case OBJECTIVECTYPE_FLOAT:
+ return "Float";
+ case OBJECTIVECTYPE_DOUBLE:
+ return "Double";
+ case OBJECTIVECTYPE_BOOLEAN:
+ return "Bool";
+ case OBJECTIVECTYPE_STRING:
+ return ""; // Want NSArray
+ case OBJECTIVECTYPE_DATA:
+ return ""; // Want NSArray
+ case OBJECTIVECTYPE_ENUM:
+ return "Enum";
+ case OBJECTIVECTYPE_MESSAGE:
+ return ""; // Want NSArray
+ }
+
+ // Some compilers report reaching end of function even though all cases of
+ // the enum are handed in the switch.
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ std::string primitive_name = PrimitiveTypeName(descriptor);
+ (*variables)["type"] = primitive_name;
+ (*variables)["storage_type"] = primitive_name;
+}
+
+} // namespace
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : SingleFieldGenerator(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : ObjCObjFieldGenerator(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+ variables_["property_storage_attribute"] = "copy";
+}
+
+PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {}
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor)
+ : RepeatedFieldGenerator(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+
+ string base_name = PrimitiveArrayTypeName(descriptor);
+ if (base_name.length()) {
+ variables_["array_storage_type"] = "GPB" + base_name + "Array";
+ } else {
+ variables_["array_storage_type"] = "NSMutableArray";
+ }
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::FinishInitialization(void) {
+ RepeatedFieldGenerator::FinishInitialization();
+ if (IsPrimitiveType(descriptor_)) {
+ // No comment needed for primitive types.
+ variables_["array_comment"] = "";
+ }
+}
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
new file mode 100644
index 00000000..9bb79343
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class PrimitiveFieldGenerator : public SingleFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+ explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~PrimitiveFieldGenerator();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+ explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~PrimitiveObjFieldGenerator();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveObjFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator {
+ friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ virtual ~RepeatedPrimitiveFieldGenerator();
+ virtual void FinishInitialization(void);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+} // namespace objectivec
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index fe697acf..a2eeee2d 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -277,27 +277,39 @@ bool Parser::ConsumeString(string* output, const char* error) {
}
}
-bool Parser::TryConsumeEndOfDeclaration(const char* text,
- const LocationRecorder* location) {
+bool Parser::TryConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location) {
if (LookingAt(text)) {
string leading, trailing;
- input_->NextWithComments(&trailing, NULL, &leading);
+ vector<string> detached;
+ input_->NextWithComments(&trailing, &detached, &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);
+ upcoming_detached_comments_.swap(detached);
+ location->AttachComments(&leading, &trailing, &detached);
+ } else if (strcmp(text, "}") == 0) {
+ // If the current location is null and we are finishing the current scope,
+ // drop pending upcoming detached comments.
+ upcoming_detached_comments_.swap(detached);
+ } else {
+ // Otherwise, append the new detached comments to the existing upcoming
+ // detached comments.
+ upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
+ detached.begin(), detached.end());
}
+
return true;
} else {
return false;
}
}
-bool Parser::ConsumeEndOfDeclaration(const char* text,
- const LocationRecorder* location) {
+bool Parser::ConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location) {
if (TryConsumeEndOfDeclaration(text, location)) {
return true;
} else {
@@ -390,7 +402,8 @@ void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
}
void Parser::LocationRecorder::AttachComments(
- string* leading, string* trailing) const {
+ string* leading, string* trailing,
+ vector<string>* detached_comments) const {
GOOGLE_CHECK(!location_->has_leading_comments());
GOOGLE_CHECK(!location_->has_trailing_comments());
@@ -400,6 +413,11 @@ void Parser::LocationRecorder::AttachComments(
if (!trailing->empty()) {
location_->mutable_trailing_comments()->swap(*trailing);
}
+ for (int i = 0; i < detached_comments->size(); ++i) {
+ location_->add_leading_detached_comments()->swap(
+ (*detached_comments)[i]);
+ }
+ detached_comments->clear();
}
// -------------------------------------------------------------------
@@ -451,16 +469,18 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
SourceCodeInfo source_code_info;
source_code_info_ = &source_code_info;
+ vector<string> top_doc_comments;
if (LookingAtType(io::Tokenizer::TYPE_START)) {
// Advance to first token.
- input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
+ input_->NextWithComments(NULL, &upcoming_detached_comments_,
+ &upcoming_doc_comments_);
}
{
LocationRecorder root_location(this);
if (require_syntax_identifier_ || LookingAt("syntax")) {
- if (!ParseSyntaxIdentifier()) {
+ if (!ParseSyntaxIdentifier(root_location)) {
// Don't attempt to parse the file if we didn't recognize the syntax
// identifier.
return false;
@@ -469,9 +489,9 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
if (file != NULL) file->set_syntax(syntax_identifier_);
} else if (!stop_after_syntax_identifier_) {
GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. "
- << "Please use 'syntax = \"proto2\";' or "
- << "'syntax = \"proto3\";' to specify a syntax "
- << "version. (Defaulted to proto2 syntax.)";
+ << "Please use 'syntax = \"proto2\";' or "
+ << "'syntax = \"proto3\";' to specify a syntax "
+ << "version. (Defaulted to proto2 syntax.)";
syntax_identifier_ = "proto2";
}
@@ -486,7 +506,8 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
if (LookingAt("}")) {
AddError("Unmatched \"}\".");
- input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
+ input_->NextWithComments(NULL, &upcoming_detached_comments_,
+ &upcoming_doc_comments_);
}
}
}
@@ -498,7 +519,9 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
return !had_errors_;
}
-bool Parser::ParseSyntaxIdentifier() {
+bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
+ LocationRecorder syntax_location(parent,
+ FileDescriptorProto::kSyntaxFieldNumber);
DO(Consume(
"syntax",
"File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
@@ -506,7 +529,7 @@ bool Parser::ParseSyntaxIdentifier() {
io::Tokenizer::Token syntax_token = input_->current();
string syntax;
DO(ConsumeString(&syntax, "Expected syntax identifier."));
- DO(ConsumeEndOfDeclaration(";", NULL));
+ DO(ConsumeEndOfDeclaration(";", &syntax_location));
syntax_identifier_ = syntax;
@@ -663,6 +686,8 @@ bool Parser::ParseMessageStatement(DescriptorProto* message,
LocationRecorder location(message_location,
DescriptorProto::kExtensionRangeFieldNumber);
return ParseExtensions(message, location, containing_file);
+ } else if (LookingAt("reserved")) {
+ return ParseReserved(message, message_location);
} else if (LookingAt("extend")) {
LocationRecorder location(message_location,
DescriptorProto::kExtensionFieldNumber);
@@ -710,6 +735,13 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field,
FieldDescriptorProto::Label label;
if (ParseLabel(&label, containing_file)) {
field->set_label(label);
+ if (label == FieldDescriptorProto::LABEL_OPTIONAL &&
+ syntax_identifier_ == "proto3") {
+ AddError(
+ "Explicit 'optional' labels are disallowed in the Proto3 syntax. "
+ "To define 'optional' fields in Proto3, simply remove the "
+ "'optional' label, as fields are 'optional' by default.");
+ }
}
}
@@ -1271,7 +1303,6 @@ bool Parser::ParseOption(Message* options,
DO(ConsumeEndOfDeclaration(";", &location));
}
-
return true;
}
@@ -1331,6 +1362,77 @@ bool Parser::ParseExtensions(DescriptorProto* message,
return true;
}
+// This is similar to extension range parsing, except that "max" is not
+// supported, and accepts field name literals.
+bool Parser::ParseReserved(DescriptorProto* message,
+ const LocationRecorder& message_location) {
+ // Parse the declaration.
+ DO(Consume("reserved"));
+ if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ LocationRecorder location(message_location,
+ DescriptorProto::kReservedNameFieldNumber);
+ return ParseReservedNames(message, location);
+ } else {
+ LocationRecorder location(message_location,
+ DescriptorProto::kReservedRangeFieldNumber);
+ return ParseReservedNumbers(message, location);
+ }
+}
+
+
+bool Parser::ParseReservedNames(DescriptorProto* message,
+ const LocationRecorder& parent_location) {
+ do {
+ LocationRecorder location(parent_location, message->reserved_name_size());
+ DO(ConsumeString(message->add_reserved_name(), "Expected field name."));
+ } while (TryConsume(","));
+ DO(ConsumeEndOfDeclaration(";", &parent_location));
+ return true;
+}
+
+bool Parser::ParseReservedNumbers(DescriptorProto* message,
+ const LocationRecorder& parent_location) {
+ bool first = true;
+ do {
+ LocationRecorder location(parent_location, message->reserved_range_size());
+
+ DescriptorProto::ReservedRange* range = message->add_reserved_range();
+ int start, end;
+ io::Tokenizer::Token start_token;
+ {
+ LocationRecorder start_location(
+ location, DescriptorProto::ReservedRange::kStartFieldNumber);
+ start_token = input_->current();
+ DO(ConsumeInteger(&start, (first ?
+ "Expected field name or number range." :
+ "Expected field number range.")));
+ }
+
+ if (TryConsume("to")) {
+ LocationRecorder end_location(
+ location, DescriptorProto::ReservedRange::kEndFieldNumber);
+ DO(ConsumeInteger(&end, "Expected integer."));
+ } else {
+ LocationRecorder end_location(
+ location, DescriptorProto::ReservedRange::kEndFieldNumber);
+ end_location.StartAt(start_token);
+ end_location.EndAt(start_token);
+ end = start;
+ }
+
+ // Users like to specify inclusive ranges, but in code we like the end
+ // number to be exclusive.
+ ++end;
+
+ range->set_start(start);
+ range->set_end(end);
+ first = false;
+ } while (TryConsume(","));
+
+ DO(ConsumeEndOfDeclaration(";", &parent_location));
+ return true;
+}
+
bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
RepeatedPtrField<DescriptorProto>* messages,
const LocationRecorder& parent_location,
@@ -1636,8 +1738,14 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
// Parse input type.
DO(Consume("("));
{
- if (TryConsume("stream")) {
+ if (LookingAt("stream")) {
+ LocationRecorder location(
+ method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
+ location.RecordLegacyLocation(
+ method, DescriptorPool::ErrorCollector::OTHER);
method->set_client_streaming(true);
+ DO(Consume("stream"));
+
}
LocationRecorder location(method_location,
MethodDescriptorProto::kInputTypeFieldNumber);
@@ -1651,8 +1759,14 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
DO(Consume("returns"));
DO(Consume("("));
{
- if (TryConsume("stream")) {
+ if (LookingAt("stream")) {
+ LocationRecorder location(
+ method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
+ location.RecordLegacyLocation(
+ method, DescriptorPool::ErrorCollector::OTHER);
+ DO(Consume("stream"));
method->set_server_streaming(true);
+
}
LocationRecorder location(method_location,
MethodDescriptorProto::kOutputTypeFieldNumber);
@@ -1664,10 +1778,9 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
if (LookingAt("{")) {
// Options!
- DO(ParseOptions(method_location,
- containing_file,
- MethodDescriptorProto::kOptionsFieldNumber,
- method->mutable_options()));
+ DO(ParseMethodOptions(method_location, containing_file,
+ MethodDescriptorProto::kOptionsFieldNumber,
+ method->mutable_options()));
} else {
DO(ConsumeEndOfDeclaration(";", &method_location));
}
@@ -1676,10 +1789,10 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
}
-bool Parser::ParseOptions(const LocationRecorder& parent_location,
- const FileDescriptorProto* containing_file,
- const int optionsFieldNumber,
- Message* mutable_options) {
+bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
+ const FileDescriptorProto* containing_file,
+ const int optionsFieldNumber,
+ Message* mutable_options) {
// Options!
ConsumeEndOfDeclaration("{", &parent_location);
while (!TryConsumeEndOfDeclaration("}", NULL)) {
@@ -1693,8 +1806,8 @@ bool Parser::ParseOptions(const LocationRecorder& parent_location,
} else {
LocationRecorder location(parent_location,
optionsFieldNumber);
- if (!ParseOption(mutable_options, location, containing_file,
- OPTION_STATEMENT)) {
+ if (!ParseOption(mutable_options, location,
+ containing_file, OPTION_STATEMENT)) {
// This statement failed to parse. Skip it, but keep looping to
// parse other statements.
SkipStatement();
@@ -1847,7 +1960,7 @@ bool SourceLocationTable::Find(
DescriptorPool::ErrorCollector::ErrorLocation location,
int* line, int* column) const {
const pair<int, int>* result =
- FindOrNull(location_map_, make_pair(descriptor, location));
+ FindOrNull(location_map_, std::make_pair(descriptor, location));
if (result == NULL) {
*line = -1;
*column = 0;
@@ -1863,7 +1976,8 @@ void SourceLocationTable::Add(
const Message* descriptor,
DescriptorPool::ErrorCollector::ErrorLocation location,
int line, int column) {
- location_map_[make_pair(descriptor, location)] = make_pair(line, column);
+ location_map_[std::make_pair(descriptor, location)] =
+ std::make_pair(line, column);
}
void SourceLocationTable::Clear() {
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index a15cc705..16012e96 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -185,10 +185,13 @@ class LIBPROTOBUF_EXPORT Parser {
// 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);
+ bool TryConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location);
+ bool TryConsumeEndOfDeclarationFinishScope(
+ const char* text, const LocationRecorder* location);
+
+ bool ConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location);
// -----------------------------------------------------------------
// Error logging helpers
@@ -253,9 +256,13 @@ class LIBPROTOBUF_EXPORT Parser {
//
// TODO(kenton): See comment on TryConsumeEndOfDeclaration(), above, for
// why this is const.
- void AttachComments(string* leading, string* trailing) const;
+ void AttachComments(string* leading, string* trailing,
+ vector<string>* detached_comments) const;
private:
+ // Indexes of parent and current location in the parent
+ // SourceCodeInfo.location repeated field. For top-level elements,
+ // parent_index_ is -1.
Parser* parser_;
SourceCodeInfo::Location* location_;
@@ -268,7 +275,7 @@ class LIBPROTOBUF_EXPORT Parser {
// Parses the "syntax = \"proto2\";" line at the top of the file. Returns
// false if it failed to parse or if the syntax identifier was not
// recognized.
- bool ParseSyntaxIdentifier();
+ bool ParseSyntaxIdentifier(const LocationRecorder& parent);
// These methods parse various individual bits of code. They return
// false if they completely fail to parse the construct. In this case,
@@ -302,9 +309,6 @@ class LIBPROTOBUF_EXPORT Parser {
RepeatedField<int32>* weak_dependency,
const LocationRecorder& root_location,
const FileDescriptorProto* containing_file);
- bool ParseOption(Message* options,
- const LocationRecorder& options_location,
- const FileDescriptorProto* containing_file);
// These methods parse the contents of a message, enum, or service type and
// add them to the given object. They consume the entire block including
@@ -360,6 +364,14 @@ class LIBPROTOBUF_EXPORT Parser {
const LocationRecorder& extensions_location,
const FileDescriptorProto* containing_file);
+ // Parse an "reserved" declaration.
+ bool ParseReserved(DescriptorProto* message,
+ const LocationRecorder& message_location);
+ bool ParseReservedNames(DescriptorProto* message,
+ const LocationRecorder& parent_location);
+ bool ParseReservedNumbers(DescriptorProto* message,
+ const LocationRecorder& parent_location);
+
// Parse an "extend" declaration. (See also comments for
// ParseMessageField().)
bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
@@ -397,10 +409,10 @@ class LIBPROTOBUF_EXPORT Parser {
// Parse options of a single method or stream.
- bool ParseOptions(const LocationRecorder& parent_location,
- const FileDescriptorProto* containing_file,
- const int optionsFieldNumber,
- Message* mutable_options);
+ bool ParseMethodOptions(const LocationRecorder& parent_location,
+ const FileDescriptorProto* containing_file,
+ const int optionsFieldNumber,
+ Message* mutable_options);
// Parse "required", "optional", or "repeated" and fill in "label"
// with the value. Returns true if shuch a label is consumed.
@@ -497,6 +509,13 @@ class LIBPROTOBUF_EXPORT Parser {
// yet; use ConsumeEndOfDeclaration() to get the complete comments.
string upcoming_doc_comments_;
+ // Detached comments are not connected to any syntax entities. Elements in
+ // this vector are paragraphs of comments separated by empty lines. The
+ // detached comments will be put into the leading_detached_comments field for
+ // the next element (See SourceCodeInfo.Location in descriptor.proto), when
+ // ConsumeEndOfDeclaration() is called.
+ vector<string> upcoming_detached_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 638a83b9..cc6f1efb 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -229,6 +229,32 @@ TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
typedef ParserTest ParseMessageTest;
+TEST_F(ParseMessageTest, IgnoreBOM) {
+ char input[] = " message TestMessage {\n"
+ " required int32 foo = 1;\n"
+ "}\n";
+ // Set UTF-8 BOM.
+ input[0] = (char)0xEF;
+ input[1] = (char)0xBB;
+ input[2] = (char)0xBF;
+ ExpectParsesTo(input,
+ "message_type {"
+ " name: \"TestMessage\""
+ " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+ "}");
+}
+
+TEST_F(ParseMessageTest, BOMError) {
+ char input[] = " message TestMessage {\n"
+ " required int32 foo = 1;\n"
+ "}\n";
+ input[0] = (char)0xEF;
+ ExpectHasErrors(input,
+ "0:1: Proto file starts with 0xEF but not UTF-8 BOM. "
+ "Only UTF-8 is accepted for proto file.\n"
+ "0:0: Expected top-level statement (e.g. \"message\").\n");
+}
+
TEST_F(ParseMessageTest, SimpleMessage) {
ExpectParsesTo(
"message TestMessage {\n"
@@ -401,13 +427,27 @@ TEST_F(ParseMessageTest, FieldDefaults) {
" field { type:TYPE_BOOL default_value:\"true\" " ETC " }"
" field { type_name:\"Foo\" default_value:\"FOO\" " ETC " }"
- " field { type:TYPE_INT32 default_value:\"2147483647\" " ETC " }"
- " field { type:TYPE_INT32 default_value:\"-2147483648\" " ETC " }"
- " field { type:TYPE_UINT32 default_value:\"4294967295\" " ETC " }"
- " field { type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC " }"
- " field { type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC " }"
- " field { type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC " }"
- " field { type:TYPE_DOUBLE default_value:\"43981\" " ETC " }"
+ " field {"
+ " type:TYPE_INT32 default_value:\"2147483647\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_INT32 default_value:\"-2147483648\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_UINT32 default_value:\"4294967295\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_DOUBLE default_value:\"43981\" " ETC
+ " }"
"}");
#undef ETC
}
@@ -606,6 +646,36 @@ TEST_F(ParseMessageTest, NestedEnum) {
"}");
}
+TEST_F(ParseMessageTest, ReservedRange) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " required int32 foo = 1;\n"
+ " reserved 2, 15, 9 to 11, 3;\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+ " reserved_range { start:2 end:3 }"
+ " reserved_range { start:15 end:16 }"
+ " reserved_range { start:9 end:12 }"
+ " reserved_range { start:3 end:4 }"
+ "}");
+}
+
+TEST_F(ParseMessageTest, ReservedNames) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " reserved \"foo\", \"bar\";\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " reserved_name: \"foo\""
+ " reserved_name: \"bar\""
+ "}");
+}
+
TEST_F(ParseMessageTest, ExtensionRange) {
ExpectParsesTo(
"message TestMessage {\n"
@@ -701,19 +771,17 @@ TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
" type_name:\"TestMessage\" extendee: \"Extendee1\" }");
}
-TEST_F(ParseMessageTest, OptionalOptionalLabelProto3) {
+TEST_F(ParseMessageTest, OptionalLabelProto3) {
ExpectParsesTo(
"syntax = \"proto3\";\n"
"message TestMessage {\n"
" int32 foo = 1;\n"
- " optional int32 bar = 2;\n"
"}\n",
"syntax: \"proto3\" "
"message_type {"
" name: \"TestMessage\""
- " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
- " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 } }");
+ " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } }");
}
// ===================================================================
@@ -1216,6 +1284,18 @@ TEST_F(ParseErrorTest, EofInAggregateValue) {
"1:0: Unexpected end of stream while parsing aggregate value.\n");
}
+TEST_F(ParseErrorTest, ExplicitOptionalLabelProto3) {
+ ExpectHasErrors(
+ "syntax = 'proto3';\n"
+ "message TestMessage {\n"
+ " optional int32 foo = 1;\n"
+ "}\n",
+ "2:11: Explicit 'optional' labels are disallowed in the Proto3 syntax. "
+ "To define 'optional' fields in Proto3, simply remove the 'optional' "
+ "label, as fields are 'optional' by default.\n");
+}
+
+
// -------------------------------------------------------------------
// Enum errors
@@ -1234,6 +1314,33 @@ TEST_F(ParseErrorTest, EnumValueMissingNumber) {
}
// -------------------------------------------------------------------
+// Reserved field number errors
+
+TEST_F(ParseErrorTest, ReservedMaxNotAllowed) {
+ ExpectHasErrors(
+ "message Foo {\n"
+ " reserved 10 to max;\n"
+ "}\n",
+ "1:17: Expected integer.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedMixNameAndNumber) {
+ ExpectHasErrors(
+ "message Foo {\n"
+ " reserved 10, \"foo\";\n"
+ "}\n",
+ "1:15: Expected field number range.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedMissingQuotes) {
+ ExpectHasErrors(
+ "message Foo {\n"
+ " reserved foo;\n"
+ "}\n",
+ "1:11: Expected field name or number range.\n");
+}
+
+// -------------------------------------------------------------------
// Service errors
TEST_F(ParseErrorTest, EofInService) {
@@ -1557,7 +1664,7 @@ void SortMessages(DescriptorProto *descriptor_proto) {
}
DescriptorProto **data =
descriptor_proto->mutable_nested_type()->mutable_data();
- sort(data, data + size, CompareDescriptorNames());
+ std::sort(data, data + size, CompareDescriptorNames());
}
// Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
@@ -1569,7 +1676,7 @@ void SortMessages(FileDescriptorProto *file_descriptor_proto) {
}
DescriptorProto **data =
file_descriptor_proto->mutable_message_type()->mutable_data();
- sort(data, data + size, CompareDescriptorNames());
+ std::sort(data, data + size, CompareDescriptorNames());
}
// Strips the message and enum field type names for comparison purpose only.
@@ -1689,25 +1796,52 @@ TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
// places.
TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
SetupParser(
+ "// Detached comment before syntax.\n"
+ "\n"
+ "// Syntax comment.\n"
+ "syntax = \"proto2\";\n"
+ "\n"
+ "// Detached comment before package.\n"
+ "\n"
+ "// Package comment.\n"
+ "package comment_test;\n"
+ "\n"
+ "// Detached comment before TestMessage1.\n"
+ "\n"
"// Message comment.\n"
"message TestMessage1 {\n"
+ "\n"
+ " // Detached comment before foo.\n"
+ "\n"
" // Field comment.\n"
" optional int32 foo = 1;\n"
"\n"
+ " // Detached comment before NestedMessage.\n"
+ "\n"
" // Nested-message comment.\n"
" message NestedMessage {\n"
" optional int32 bar = 1;\n"
" }\n"
"}\n"
"\n"
+ "// Detached comment before MyEnumType.\n"
+ "\n"
"// Enum comment.\n"
"enum MyEnumType {\n"
+ "\n"
+ " // Detached comment before ASDF.\n"
+ "\n"
" // Enum-value comment.\n"
" ASDF = 1;\n"
"}\n"
"\n"
+ "// Detached comment before MyService.\n"
+ "\n"
"// Service comment.\n"
"service MyService {\n"
+ "\n"
+ " // Detached comment before MyRPCCall.\n"
+ "\n"
" // RPC comment.\n"
" rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
"}\n");
@@ -1731,22 +1865,34 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
const string debug_string =
descriptor->DebugStringWithOptions(debug_string_options);
- // Ensure that each of the comments appears somewhere in the DebugString(),
- // and that these comments appear in order. We don't test the exact comment
- // placement or formatting, because we do not want to be too fragile here.
+ // Ensure that each of the comments appears somewhere in the DebugString().
+ // We don't test the exact comment placement or formatting, because we do not
+ // want to be too fragile here.
const char* expected_comments[] = {
+ "Detached comment before syntax.",
+ "Syntax comment.",
+ "Detached comment before package.",
+ "Package comment.",
+ "Detached comment before TestMessage1.",
"Message comment.",
+ "Detached comment before foo.",
"Field comment",
+ "Detached comment before NestedMessage.",
"Nested-message comment",
+ "Detached comment before MyEnumType.",
"Enum comment",
+ "Detached comment before ASDF.",
"Enum-value comment",
+ "Detached comment before MyService.",
"Service comment",
+ "Detached comment before MyRPCCall.",
"RPC comment",
};
for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
string::size_type found_pos = debug_string.find(expected_comments[i]);
- ASSERT_TRUE(found_pos != string::npos);
+ EXPECT_TRUE(found_pos != string::npos)
+ << "\"" << expected_comments[i] << "\" not found.";
}
}
@@ -1916,8 +2062,8 @@ class SourceInfoTest : public ParserTest {
return false;
}
- spans_.insert(make_pair(SpanKey(*descriptor_proto, field, index),
- &location));
+ spans_.insert(
+ std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
}
return true;
@@ -1938,16 +2084,18 @@ class SourceInfoTest : public ParserTest {
bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto) {
return HasSpanWithComment(
- start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL);
+ start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL, NULL);
}
bool HasSpanWithComment(char start_marker, char end_marker,
const Message& descriptor_proto,
const char* expected_leading_comments,
- const char* expected_trailing_comments) {
+ const char* expected_trailing_comments,
+ const char* expected_leading_detached_comments) {
return HasSpanWithComment(
start_marker, end_marker, descriptor_proto, NULL, -1,
- expected_leading_comments, expected_trailing_comments);
+ expected_leading_comments, expected_trailing_comments,
+ expected_leading_detached_comments);
}
bool HasSpan(char start_marker, char end_marker,
@@ -1959,14 +2107,15 @@ class SourceInfoTest : public ParserTest {
const Message& descriptor_proto, const string& field_name,
int index) {
return HasSpan(start_marker, end_marker, descriptor_proto,
- field_name, index, NULL, NULL);
+ field_name, index, NULL, 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 char* expected_trailing_comments,
+ const char* expected_leading_detached_comments) {
const FieldDescriptor* field =
descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
if (field == NULL) {
@@ -1977,12 +2126,13 @@ class SourceInfoTest : public ParserTest {
return HasSpanWithComment(
start_marker, end_marker, descriptor_proto, field, index,
- expected_leading_comments, expected_trailing_comments);
+ expected_leading_comments, expected_trailing_comments,
+ expected_leading_detached_comments);
}
bool HasSpan(const Message& descriptor_proto) {
return HasSpanWithComment(
- '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL);
+ '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL, NULL);
}
bool HasSpan(const Message& descriptor_proto, const string& field_name) {
@@ -1994,11 +2144,12 @@ class SourceInfoTest : public ParserTest {
return HasSpan('\0', '\0', descriptor_proto, field_name, 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) {
+ 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,
+ const char* expected_leading_detached_comments) {
pair<SpanMap::iterator, SpanMap::iterator> range =
spans_.equal_range(SpanKey(descriptor_proto, field, index));
@@ -2037,6 +2188,13 @@ class SourceInfoTest : public ParserTest {
EXPECT_EQ(expected_trailing_comments,
iter->second->trailing_comments());
}
+ if (expected_leading_detached_comments == NULL) {
+ EXPECT_EQ(0, iter->second->leading_detached_comments_size());
+ } else {
+ EXPECT_EQ(
+ expected_leading_detached_comments,
+ Join(iter->second->leading_detached_comments(), "\n"));
+ }
spans_.erase(iter);
return true;
@@ -2087,7 +2245,7 @@ class SourceInfoTest : public ParserTest {
text_without_markers_ += '$';
++column;
} else {
- markers_[*text] = make_pair(line, column);
+ markers_[*text] = std::make_pair(line, column);
++text;
GOOGLE_CHECK_EQ('$', *text);
}
@@ -2106,7 +2264,7 @@ class SourceInfoTest : public ParserTest {
TEST_F(SourceInfoTest, BasicFileDecls) {
EXPECT_TRUE(Parse(
- "$a$syntax = \"proto2\";\n"
+ "$a$syntax = \"proto2\";$i$\n"
"package $b$foo.bar$c$;\n"
"import $d$\"baz.proto\"$e$;\n"
"import $f$\"qux.proto\"$g$;$h$\n"
@@ -2117,6 +2275,7 @@ TEST_F(SourceInfoTest, BasicFileDecls) {
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', 'i', file_, "syntax"));
}
TEST_F(SourceInfoTest, Messages) {
@@ -2547,6 +2706,9 @@ TEST_F(SourceInfoTest, ScopedOptions) {
" rpc M(X) returns(Y) {\n"
" $g$option mopt = 1;$h$\n"
" }\n"
+ " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
+ " $k$option mopt = 1;$l$\n"
+ " }\n"
"}\n"));
EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
@@ -2606,6 +2768,26 @@ TEST_F(SourceInfoTest, ScopedOptions) {
.uninterpreted_option(0).name(0), "name_part"));
EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
.uninterpreted_option(0), "positive_int_value"));
+
+ EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0)));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0), "name"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0).name(0)));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0).name(0), "name_part"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0), "positive_int_value"));
+ EXPECT_TRUE(HasSpan('1', '2', file_.service(0).method(1),
+ "client_streaming"));
+ EXPECT_TRUE(HasSpan('3', '4', file_.service(0).method(1),
+ "server_streaming"));
}
TEST_F(SourceInfoTest, FieldOptions) {
@@ -2691,7 +2873,7 @@ TEST_F(SourceInfoTest, DocComments) {
" // Foo trailing\n"
" // line 2\n"
"\n"
- " // ignored\n"
+ " // detached\n"
"\n"
" // bar leading\n"
" $b$optional int32 bar = 1;$c$\n"
@@ -2705,10 +2887,12 @@ TEST_F(SourceInfoTest, DocComments) {
EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
" Foo leading\n line 2\n",
- " Foo trailing\n line 2\n"));
+ " Foo trailing\n line 2\n",
+ NULL));
EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
" bar leading\n",
- " bar trailing\n"));
+ " bar trailing\n",
+ " detached\n"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2721,21 +2905,23 @@ TEST_F(SourceInfoTest, DocComments) {
TEST_F(SourceInfoTest, DocComments2) {
EXPECT_TRUE(Parse(
- "// ignored\n"
- "syntax = \"proto2\";\n"
+ "// detached before message.\n"
+ "\n"
"// Foo leading\n"
"// line 2\n"
"$a$message Foo {\n"
" /* Foo trailing\n"
" * line 2 */\n"
- " // ignored\n"
+ " // detached\n"
" /* bar leading\n"
" */"
" $b$optional int32 bar = 1;$c$ // bar trailing\n"
- " // ignored\n"
+ " // ignored detached\n"
"}$d$\n"
"// ignored\n"
"\n"
+ "// detached before option\n"
+ "\n"
"// option leading\n"
"$e$option baz = 123;$f$\n"
"// option trailing\n"
@@ -2747,13 +2933,16 @@ TEST_F(SourceInfoTest, DocComments2) {
EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
" Foo leading\n line 2\n",
- " Foo trailing\n line 2 "));
+ " Foo trailing\n line 2 ",
+ " detached before message.\n"));
EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
" bar leading\n",
- " bar trailing\n"));
+ " bar trailing\n",
+ " detached\n"));
EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
" option leading\n",
- " option trailing\n"));
+ " option trailing\n",
+ " detached before option\n"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2784,7 +2973,8 @@ TEST_F(SourceInfoTest, DocComments3) {
EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
" bar leading\n",
- " bar trailing\n"));
+ " bar trailing\n",
+ NULL));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2804,25 +2994,63 @@ TEST_F(SourceInfoTest, DocComments3) {
bar.options().uninterpreted_option(0), "aggregate_value"));
}
+TEST_F(SourceInfoTest, DocCommentsTopLevel) {
+ EXPECT_TRUE(Parse(
+ "// detached before syntax paragraph 1\n"
+ "\n"
+ "// detached before syntax paragraph 2\n"
+ "\n"
+ "// syntax leading\n"
+ "$a$syntax = \"proto2\";$b$\n"
+ "// syntax trailing\n"
+ "\n"
+ "// syntax-package detached comments\n"
+ "\n"
+ ";\n"
+ "\n"
+ "// detached after empty before package\n"
+ "\n"
+ "// package leading\n"
+ "package $c$foo$d$;\n"
+ "// package trailing\n"
+ "\n"
+ "// ignored detach\n"
+ "\n"));
+
+ EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1,
+ " syntax leading\n",
+ " syntax trailing\n",
+ " detached before syntax paragraph 1\n"
+ "\n"
+ " detached before syntax paragraph 2\n"));
+ EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1,
+ " package leading\n",
+ " package trailing\n",
+ " syntax-package detached comments\n"
+ "\n"
+ " detached after empty before package\n"));
+
+ // ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+}
+
TEST_F(SourceInfoTest, DocCommentsOneof) {
EXPECT_TRUE(Parse(
- "// ignored\n"
- "syntax = \"proto2\";\n"
"// Foo leading\n"
"$a$message Foo {\n"
" /* Foo trailing\n"
" */\n"
- " // ignored\n"
+ " // detached before oneof\n"
" /* bar leading\n"
" * line 2 */\n"
" $b$oneof bar {\n"
" /* bar trailing\n"
" * line 2 */\n"
- " // ignored\n"
+ " // detached before bar_int\n"
" /* bar_int leading\n"
" */\n"
" $c$int32 bar_int = 1;$d$ // bar_int trailing\n"
- " // ignored\n"
+ " // detach comment ignored\n"
" }$e$\n"
"}$f$\n"));
@@ -2832,13 +3060,16 @@ TEST_F(SourceInfoTest, DocCommentsOneof) {
EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
" Foo leading\n",
- " Foo trailing\n"));
+ " Foo trailing\n",
+ NULL));
EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
" bar leading\n line 2 ",
- " bar trailing\n line 2 "));
+ " bar trailing\n line 2 ",
+ " detached before oneof\n"));
EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
" bar_int leading\n",
- " bar_int trailing\n"));
+ " bar_int trailing\n",
+ " detached before bar_int\n"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index 9011a6bd..cdcaffde 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -95,7 +95,7 @@ class GeneratorResponseContext : public GeneratorContext {
int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
if (argc > 1) {
- cerr << argv[0] << ": Unknown option: " << argv[1] << endl;
+ std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
return 1;
}
@@ -106,7 +106,8 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
CodeGeneratorRequest request;
if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
- cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl;
+ std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
+ << std::endl;
return 1;
}
@@ -123,9 +124,9 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
for (int i = 0; i < request.file_to_generate_size(); i++) {
parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
if (parsed_files.back() == NULL) {
- cerr << argv[0] << ": protoc asked plugin to generate a file but "
- "did not provide a descriptor for the file: "
- << request.file_to_generate(i) << endl;
+ std::cerr << argv[0] << ": protoc asked plugin to generate a file but "
+ "did not provide a descriptor for the file: "
+ << request.file_to_generate(i) << std::endl;
return 1;
}
}
@@ -133,25 +134,39 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
CodeGeneratorResponse response;
GeneratorResponseContext context(&response, parsed_files);
- for (int i = 0; i < parsed_files.size(); i++) {
- const FileDescriptor* file = parsed_files[i];
-
+ if (generator->HasGenerateAll()) {
string error;
- bool succeeded = generator->Generate(
- file, request.parameter(), &context, &error);
+ bool succeeded = generator->GenerateAll(
+ parsed_files, request.parameter(), &context, &error);
if (!succeeded && error.empty()) {
error = "Code generator returned false but provided no error "
"description.";
}
if (!error.empty()) {
- response.set_error(file->name() + ": " + error);
- break;
+ response.set_error(error);
+ }
+ } else {
+ for (int i = 0; i < parsed_files.size(); i++) {
+ const FileDescriptor* file = parsed_files[i];
+
+ string error;
+ bool succeeded = generator->Generate(
+ file, request.parameter(), &context, &error);
+
+ if (!succeeded && error.empty()) {
+ error = "Code generator returned false but provided no error "
+ "description.";
+ }
+ if (!error.empty()) {
+ response.set_error(file->name() + ": " + error);
+ break;
+ }
}
}
if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
- cerr << argv[0] << ": Error writing to stdout." << endl;
+ std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
return 1;
}
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 5118de15..e7890fae 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -140,8 +140,8 @@ void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
"\01324.google.protobuf.compiler.CodeGenerat"
"orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n"
"\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
- ",\n\034com.google.protobuf.compilerB\014PluginP"
- "rotos", 445);
+ "7\n\034com.google.protobuf.compilerB\014PluginP"
+ "rotosZ\tplugin_go", 456);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
@@ -179,7 +179,7 @@ const int CodeGeneratorRequest::kProtoFileFieldNumber;
#endif // !_MSC_VER
CodeGeneratorRequest::CodeGeneratorRequest()
- : ::google::protobuf::Message() , _internal_metadata_(NULL) {
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest)
}
@@ -300,12 +300,15 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
case 15: {
if (tag == 122) {
parse_proto_file:
- DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ DO_(input->IncrementRecursionDepth());
+ parse_loop_proto_file:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
input, add_proto_file()));
} else {
goto handle_unusual;
}
- if (input->ExpectTag(122)) goto parse_proto_file;
+ if (input->ExpectTag(122)) goto parse_loop_proto_file;
+ input->UnsafeDecrementRecursionDepth();
if (input->ExpectAtEnd()) goto success;
break;
}
@@ -445,9 +448,9 @@ int CodeGeneratorRequest::ByteSize() const {
void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
- const CodeGeneratorRequest* source =
- ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorRequest*>(
- &from);
+ const CodeGeneratorRequest* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>(
+ &from);
if (source == NULL) {
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
@@ -509,6 +512,147 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorRequest
+
+// repeated string file_to_generate = 1;
+int CodeGeneratorRequest::file_to_generate_size() const {
+ return file_to_generate_.size();
+}
+void CodeGeneratorRequest::clear_file_to_generate() {
+ file_to_generate_.Clear();
+}
+ const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return file_to_generate_.Get(index);
+}
+ ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return file_to_generate_.Mutable(index);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ file_to_generate_.Mutable(index)->assign(value);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
+ file_to_generate_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
+ file_to_generate_.Mutable(index)->assign(
+ reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ ::std::string* CodeGeneratorRequest::add_file_to_generate() {
+ return file_to_generate_.Add();
+}
+ void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
+ file_to_generate_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value) {
+ file_to_generate_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
+ file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+CodeGeneratorRequest::file_to_generate() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return file_to_generate_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+CodeGeneratorRequest::mutable_file_to_generate() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return &file_to_generate_;
+}
+
+// optional string parameter = 2;
+bool CodeGeneratorRequest::has_parameter() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void CodeGeneratorRequest::set_has_parameter() {
+ _has_bits_[0] |= 0x00000002u;
+}
+void CodeGeneratorRequest::clear_has_parameter() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+void CodeGeneratorRequest::clear_parameter() {
+ parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_parameter();
+}
+ const ::std::string& CodeGeneratorRequest::parameter() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+ return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
+ set_has_parameter();
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value) {
+ set_has_parameter();
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
+ set_has_parameter();
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ ::std::string* CodeGeneratorRequest::mutable_parameter() {
+ set_has_parameter();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+ return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorRequest::release_parameter() {
+ clear_has_parameter();
+ return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
+ if (parameter != NULL) {
+ set_has_parameter();
+ } else {
+ clear_has_parameter();
+ }
+ parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+
+// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+int CodeGeneratorRequest::proto_file_size() const {
+ return proto_file_.size();
+}
+void CodeGeneratorRequest::clear_proto_file() {
+ proto_file_.Clear();
+}
+ const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_.Get(index);
+}
+ ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_.Mutable(index);
+}
+ ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+CodeGeneratorRequest::proto_file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+CodeGeneratorRequest::mutable_proto_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return &proto_file_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -519,7 +663,7 @@ const int CodeGeneratorResponse_File::kContentFieldNumber;
#endif // !_MSC_VER
CodeGeneratorResponse_File::CodeGeneratorResponse_File()
- : ::google::protobuf::Message() , _internal_metadata_(NULL) {
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
}
@@ -583,7 +727,7 @@ CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf::
}
void CodeGeneratorResponse_File::Clear() {
- if (_has_bits_[0 / 32] & 7) {
+ if (_has_bits_[0 / 32] & 7u) {
if (has_name()) {
name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
@@ -769,7 +913,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
int CodeGeneratorResponse_File::ByteSize() const {
int total_size = 0;
- if (_has_bits_[0 / 32] & 7) {
+ if (_has_bits_[0 / 32] & 7u) {
// optional string name = 1;
if (has_name()) {
total_size += 1 +
@@ -805,9 +949,9 @@ int CodeGeneratorResponse_File::ByteSize() const {
void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) {
if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
- const CodeGeneratorResponse_File* source =
- ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse_File*>(
- &from);
+ const CodeGeneratorResponse_File* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>(
+ &from);
if (source == NULL) {
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
@@ -883,7 +1027,7 @@ const int CodeGeneratorResponse::kFileFieldNumber;
#endif // !_MSC_VER
CodeGeneratorResponse::CodeGeneratorResponse()
- : ::google::protobuf::Message() , _internal_metadata_(NULL) {
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse)
}
@@ -983,12 +1127,15 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
case 15: {
if (tag == 122) {
parse_file:
- DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ DO_(input->IncrementRecursionDepth());
+ parse_loop_file:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
input, add_file()));
} else {
goto handle_unusual;
}
- if (input->ExpectTag(122)) goto parse_file;
+ if (input->ExpectTag(122)) goto parse_loop_file;
+ input->UnsafeDecrementRecursionDepth();
if (input->ExpectAtEnd()) goto success;
break;
}
@@ -1101,9 +1248,9 @@ int CodeGeneratorResponse::ByteSize() const {
void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
- const CodeGeneratorResponse* source =
- ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse*>(
- &from);
+ const CodeGeneratorResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>(
+ &from);
if (source == NULL) {
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
@@ -1162,6 +1309,256 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorResponse_File
+
+// optional string name = 1;
+bool CodeGeneratorResponse_File::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void CodeGeneratorResponse_File::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+void CodeGeneratorResponse_File::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+void CodeGeneratorResponse_File::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& CodeGeneratorResponse_File::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+
+// optional string insertion_point = 2;
+bool CodeGeneratorResponse_File::has_insertion_point() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void CodeGeneratorResponse_File::set_has_insertion_point() {
+ _has_bits_[0] |= 0x00000002u;
+}
+void CodeGeneratorResponse_File::clear_has_insertion_point() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+void CodeGeneratorResponse_File::clear_insertion_point() {
+ insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_insertion_point();
+}
+ const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+ return insertion_point_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
+ set_has_insertion_point();
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
+ set_has_insertion_point();
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
+ set_has_insertion_point();
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+ set_has_insertion_point();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+ return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
+ clear_has_insertion_point();
+ return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
+ if (insertion_point != NULL) {
+ set_has_insertion_point();
+ } else {
+ clear_has_insertion_point();
+ }
+ insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+
+// optional string content = 15;
+bool CodeGeneratorResponse_File::has_content() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void CodeGeneratorResponse_File::set_has_content() {
+ _has_bits_[0] |= 0x00000004u;
+}
+void CodeGeneratorResponse_File::clear_has_content() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+void CodeGeneratorResponse_File::clear_content() {
+ content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_content();
+}
+ const ::std::string& CodeGeneratorResponse_File::content() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+ return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
+ set_has_content();
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value) {
+ set_has_content();
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
+ set_has_content();
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_content() {
+ set_has_content();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+ return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_content() {
+ clear_has_content();
+ return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
+ if (content != NULL) {
+ set_has_content();
+ } else {
+ clear_has_content();
+ }
+ content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorResponse
+
+// optional string error = 1;
+bool CodeGeneratorResponse::has_error() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void CodeGeneratorResponse::set_has_error() {
+ _has_bits_[0] |= 0x00000001u;
+}
+void CodeGeneratorResponse::clear_has_error() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+void CodeGeneratorResponse::clear_error() {
+ error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_error();
+}
+ const ::std::string& CodeGeneratorResponse::error() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
+ return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_error(const ::std::string& value) {
+ set_has_error();
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value) {
+ set_has_error();
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value, size_t size) {
+ set_has_error();
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ ::std::string* CodeGeneratorResponse::mutable_error() {
+ set_has_error();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+ return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse::release_error() {
+ clear_has_error();
+ return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
+ if (error != NULL) {
+ set_has_error();
+ } else {
+ clear_has_error();
+ }
+ error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+
+// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+int CodeGeneratorResponse::file_size() const {
+ return file_.size();
+}
+void CodeGeneratorResponse::clear_file() {
+ file_.Clear();
+}
+ const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_.Get(index);
+}
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_.Mutable(index);
+}
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+CodeGeneratorResponse::file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+CodeGeneratorResponse::mutable_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return &file_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index ad017005..6fcaea2e 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -110,43 +110,43 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
// accessors -------------------------------------------------------
// repeated string file_to_generate = 1;
- inline int file_to_generate_size() const;
- inline void clear_file_to_generate();
+ int file_to_generate_size() const;
+ void clear_file_to_generate();
static const int kFileToGenerateFieldNumber = 1;
- inline const ::std::string& file_to_generate(int index) const;
- inline ::std::string* mutable_file_to_generate(int index);
- inline void set_file_to_generate(int index, const ::std::string& value);
- inline void set_file_to_generate(int index, const char* value);
- inline void set_file_to_generate(int index, const char* value, size_t size);
- inline ::std::string* add_file_to_generate();
- inline void add_file_to_generate(const ::std::string& value);
- inline void add_file_to_generate(const char* value);
- 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();
+ const ::std::string& file_to_generate(int index) const;
+ ::std::string* mutable_file_to_generate(int index);
+ void set_file_to_generate(int index, const ::std::string& value);
+ void set_file_to_generate(int index, const char* value);
+ void set_file_to_generate(int index, const char* value, size_t size);
+ ::std::string* add_file_to_generate();
+ void add_file_to_generate(const ::std::string& value);
+ void add_file_to_generate(const char* value);
+ void add_file_to_generate(const char* value, size_t size);
+ const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
+ ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
// optional string parameter = 2;
- inline bool has_parameter() const;
- inline void clear_parameter();
+ bool has_parameter() const;
+ void clear_parameter();
static const int kParameterFieldNumber = 2;
- inline const ::std::string& parameter() const;
- inline void set_parameter(const ::std::string& value);
- inline void set_parameter(const char* value);
- 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);
+ const ::std::string& parameter() const;
+ void set_parameter(const ::std::string& value);
+ void set_parameter(const char* value);
+ void set_parameter(const char* value, size_t size);
+ ::std::string* mutable_parameter();
+ ::std::string* release_parameter();
+ 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();
+ int proto_file_size() const;
+ void clear_proto_file();
static const int kProtoFileFieldNumber = 15;
- inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
- inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
- inline ::google::protobuf::FileDescriptorProto* add_proto_file();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+ const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
+ ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
+ ::google::protobuf::FileDescriptorProto* add_proto_file();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
proto_file() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
mutable_proto_file();
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
@@ -234,40 +234,40 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
// accessors -------------------------------------------------------
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- 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);
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
// optional string insertion_point = 2;
- inline bool has_insertion_point() const;
- inline void clear_insertion_point();
+ bool has_insertion_point() const;
+ void clear_insertion_point();
static const int kInsertionPointFieldNumber = 2;
- inline const ::std::string& insertion_point() const;
- inline void set_insertion_point(const ::std::string& value);
- inline void set_insertion_point(const char* value);
- 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);
+ const ::std::string& insertion_point() const;
+ void set_insertion_point(const ::std::string& value);
+ void set_insertion_point(const char* value);
+ void set_insertion_point(const char* value, size_t size);
+ ::std::string* mutable_insertion_point();
+ ::std::string* release_insertion_point();
+ void set_allocated_insertion_point(::std::string* insertion_point);
// optional string content = 15;
- inline bool has_content() const;
- inline void clear_content();
+ bool has_content() const;
+ void clear_content();
static const int kContentFieldNumber = 15;
- inline const ::std::string& content() const;
- inline void set_content(const ::std::string& value);
- inline void set_content(const char* value);
- 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);
+ const ::std::string& content() const;
+ void set_content(const ::std::string& value);
+ void set_content(const char* value);
+ void set_content(const char* value, size_t size);
+ ::std::string* mutable_content();
+ ::std::string* release_content();
+ void set_allocated_content(::std::string* content);
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
private:
@@ -360,27 +360,27 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
// accessors -------------------------------------------------------
// optional string error = 1;
- inline bool has_error() const;
- inline void clear_error();
+ bool has_error() const;
+ void clear_error();
static const int kErrorFieldNumber = 1;
- inline const ::std::string& error() const;
- inline void set_error(const ::std::string& value);
- inline void set_error(const char* value);
- 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);
+ const ::std::string& error() const;
+ void set_error(const ::std::string& value);
+ void set_error(const char* value);
+ void set_error(const char* value, size_t size);
+ ::std::string* mutable_error();
+ ::std::string* release_error();
+ void set_allocated_error(::std::string* error);
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
- inline int file_size() const;
- inline void clear_file();
+ int file_size() const;
+ void clear_file();
static const int kFileFieldNumber = 15;
- inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
- inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
- inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+ const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
file() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
mutable_file();
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
@@ -405,6 +405,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
// ===================================================================
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
// CodeGeneratorRequest
// repeated string file_to_generate = 1;
@@ -794,21 +795,17 @@ CodeGeneratorResponse::mutable_file() {
return &file_;
}
+#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
-// @@protoc_insertion_point(namespace_scope)
-
-} // namespace compiler
-} // namespace protobuf
-} // namespace google
+// -------------------------------------------------------------------
-#ifndef SWIG
-namespace google {
-namespace protobuf {
+// @@protoc_insertion_point(namespace_scope)
+} // namespace compiler
} // namespace protobuf
} // namespace google
-#endif // SWIG
// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto
index e627289b..acaee1f4 100644
--- a/src/google/protobuf/compiler/plugin.proto
+++ b/src/google/protobuf/compiler/plugin.proto
@@ -49,6 +49,8 @@ package google.protobuf.compiler;
option java_package = "com.google.protobuf.compiler";
option java_outer_classname = "PluginProtos";
+option go_package = "plugin_go";
+
import "google/protobuf/descriptor.proto";
// An encoded CodeGeneratorRequest is written to the plugin's stdin.
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index b30d1972..7b3b5fa3 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -273,6 +273,19 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
return "";
}
+string StringifySyntax(FileDescriptor::Syntax syntax) {
+ switch (syntax) {
+ case FileDescriptor::SYNTAX_PROTO2:
+ return "proto2";
+ case FileDescriptor::SYNTAX_PROTO3:
+ return "proto3";
+ case FileDescriptor::SYNTAX_UNKNOWN:
+ default:
+ GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports proto2 "
+ "and proto3 syntax.";
+ return "";
+ }
+}
} // namespace
@@ -367,10 +380,12 @@ void Generator::PrintFileDescriptor() const {
m["descriptor_name"] = kDescriptorKey;
m["name"] = file_->name();
m["package"] = file_->package();
+ m["syntax"] = StringifySyntax(file_->syntax());
const char file_descriptor_template[] =
"$descriptor_name$ = _descriptor.FileDescriptor(\n"
" name='$name$',\n"
- " package='$package$',\n";
+ " package='$package$',\n"
+ " syntax='$syntax$',\n";
printer_->Print(m, file_descriptor_template);
printer_->Indent();
printer_->Print(
@@ -414,7 +429,7 @@ void Generator::PrintTopLevelEnums() const {
for (int j = 0; j < enum_descriptor.value_count(); ++j) {
const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j);
top_level_enum_values.push_back(
- make_pair(value_descriptor.name(), value_descriptor.number()));
+ std::make_pair(value_descriptor.name(), value_descriptor.number()));
}
}
@@ -581,14 +596,15 @@ void Generator::PrintServiceDescriptor(
}
-void Generator::PrintDescriptorKeyAndModuleName(const ServiceDescriptor& descriptor) const {
+void Generator::PrintDescriptorKeyAndModuleName(
+ const ServiceDescriptor& descriptor) const {
printer_->Print(
"$descriptor_key$ = $descriptor_name$,\n",
"descriptor_key", kDescriptorKey,
"descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
printer_->Print(
"__module__ = '$module_name$'\n",
- "module_name", ModuleName(file_->name()));
+ "module_name", ModuleName(file_->name()));
}
void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
@@ -664,10 +680,12 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
message_descriptor.options().SerializeToString(&options_string);
printer_->Print(
"options=$options_value$,\n"
- "is_extendable=$extendable$",
+ "is_extendable=$extendable$,\n"
+ "syntax='$syntax$'",
"options_value", OptionsValue("MessageOptions", options_string),
"extendable", message_descriptor.extension_range_count() > 0 ?
- "True" : "False");
+ "True" : "False",
+ "syntax", StringifySyntax(message_descriptor.file()->syntax()));
printer_->Print(",\n");
// Extension ranges
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index ee68ad72..2ddac601 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -127,7 +127,8 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const;
void PrintServiceClass(const ServiceDescriptor& descriptor) const;
void PrintServiceStub(const ServiceDescriptor& descriptor) const;
- void PrintDescriptorKeyAndModuleName(const ServiceDescriptor& descriptor) const ;
+ void PrintDescriptorKeyAndModuleName(
+ const ServiceDescriptor& descriptor) const ;
void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const;
string OptionsValue(const string& class_name,
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code.proto b/src/google/protobuf/compiler/ruby/ruby_generated_code.proto
new file mode 100644
index 00000000..42d82a6b
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code.proto
@@ -0,0 +1,67 @@
+syntax = "proto3";
+
+package A.B.C;
+
+message TestMessage {
+ int32 optional_int32 = 1;
+ int64 optional_int64 = 2;
+ uint32 optional_uint32 = 3;
+ uint64 optional_uint64 = 4;
+ bool optional_bool = 5;
+ double optional_double = 6;
+ float optional_float = 7;
+ string optional_string = 8;
+ bytes optional_bytes = 9;
+ TestEnum optional_enum = 10;
+ TestMessage optional_msg = 11;
+
+ repeated int32 repeated_int32 = 21;
+ repeated int64 repeated_int64 = 22;
+ repeated uint32 repeated_uint32 = 23;
+ repeated uint64 repeated_uint64 = 24;
+ repeated bool repeated_bool = 25;
+ repeated double repeated_double = 26;
+ repeated float repeated_float = 27;
+ repeated string repeated_string = 28;
+ repeated bytes repeated_bytes = 29;
+ repeated TestEnum repeated_enum = 30;
+ repeated TestMessage repeated_msg = 31;
+
+ oneof my_oneof {
+ int32 oneof_int32 = 41;
+ int64 oneof_int64 = 42;
+ uint32 oneof_uint32 = 43;
+ uint64 oneof_uint64 = 44;
+ bool oneof_bool = 45;
+ double oneof_double = 46;
+ float oneof_float = 47;
+ string oneof_string = 48;
+ bytes oneof_bytes = 49;
+ TestEnum oneof_enum = 50;
+ TestMessage oneof_msg = 51;
+ }
+
+ map<int32, string> map_int32_string = 61;
+ map<int64, string> map_int64_string = 62;
+ map<uint32, string> map_uint32_string = 63;
+ map<uint64, string> map_uint64_string = 64;
+ map<bool, string> map_bool_string = 65;
+ map<string, string> map_string_string = 66;
+ map<string, TestMessage> map_string_msg = 67;
+ map<string, TestEnum> map_string_enum = 68;
+ map<string, int32> map_string_int32 = 69;
+ map<string, bool> map_string_bool = 70;
+
+ message NestedMessage {
+ int32 foo = 1;
+ }
+
+ NestedMessage nested_message = 80;
+}
+
+enum TestEnum {
+ Default = 0;
+ A = 1;
+ B = 2;
+ C = 3;
+}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code.rb
new file mode 100644
index 00000000..49b23fbe
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code.rb
@@ -0,0 +1,74 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: ruby_generated_code.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "A.B.C.TestMessage" do
+ optional :optional_int32, :int32, 1
+ optional :optional_int64, :int64, 2
+ optional :optional_uint32, :uint32, 3
+ optional :optional_uint64, :uint64, 4
+ optional :optional_bool, :bool, 5
+ optional :optional_double, :double, 6
+ optional :optional_float, :float, 7
+ optional :optional_string, :string, 8
+ optional :optional_bytes, :bytes, 9
+ optional :optional_enum, :enum, 10, "A.B.C.TestEnum"
+ optional :optional_msg, :message, 11, "A.B.C.TestMessage"
+ repeated :repeated_int32, :int32, 21
+ repeated :repeated_int64, :int64, 22
+ repeated :repeated_uint32, :uint32, 23
+ repeated :repeated_uint64, :uint64, 24
+ repeated :repeated_bool, :bool, 25
+ repeated :repeated_double, :double, 26
+ repeated :repeated_float, :float, 27
+ repeated :repeated_string, :string, 28
+ repeated :repeated_bytes, :bytes, 29
+ repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum"
+ repeated :repeated_msg, :message, 31, "A.B.C.TestMessage"
+ map :map_int32_string, :int32, :string, 61
+ map :map_int64_string, :int64, :string, 62
+ map :map_uint32_string, :uint32, :string, 63
+ map :map_uint64_string, :uint64, :string, 64
+ map :map_bool_string, :bool, :string, 65
+ map :map_string_string, :string, :string, 66
+ map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage"
+ map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum"
+ map :map_string_int32, :string, :int32, 69
+ map :map_string_bool, :string, :bool, 70
+ optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
+ oneof :my_oneof do
+ optional :oneof_int32, :int32, 41
+ optional :oneof_int64, :int64, 42
+ optional :oneof_uint32, :uint32, 43
+ optional :oneof_uint64, :uint64, 44
+ optional :oneof_bool, :bool, 45
+ optional :oneof_double, :double, 46
+ optional :oneof_float, :float, 47
+ optional :oneof_string, :string, 48
+ optional :oneof_bytes, :bytes, 49
+ optional :oneof_enum, :enum, 50, "A.B.C.TestEnum"
+ optional :oneof_msg, :message, 51, "A.B.C.TestMessage"
+ end
+ end
+ add_message "A.B.C.TestMessage.NestedMessage" do
+ optional :foo, :int32, 1
+ end
+ add_enum "A.B.C.TestEnum" do
+ value :Default, 0
+ value :A, 1
+ value :B, 2
+ value :C, 3
+ end
+end
+
+module A
+ module B
+ module C
+ TestMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass
+ TestMessage::NestedMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass
+ TestEnum = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule
+ end
+ end
+end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
index c5687903..9692f1bf 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -47,7 +47,7 @@ namespace compiler {
namespace ruby {
// Forward decls.
-std::string IntToString(uint32_t value);
+std::string IntToString(int32 value);
std::string StripDotProto(const std::string& proto_file);
std::string LabelForField(google::protobuf::FieldDescriptor* field);
std::string TypeName(google::protobuf::FieldDescriptor* field);
@@ -64,7 +64,7 @@ void GenerateEnumAssignment(
const google::protobuf::EnumDescriptor* en,
google::protobuf::io::Printer* printer);
-std::string IntToString(uint32_t value) {
+std::string IntToString(int32 value) {
std::ostringstream os;
os << value;
return os.str();
@@ -85,30 +85,58 @@ std::string LabelForField(const google::protobuf::FieldDescriptor* field) {
}
std::string TypeName(const google::protobuf::FieldDescriptor* field) {
- switch (field->cpp_type()) {
- case FieldDescriptor::CPPTYPE_INT32: return "int32";
- case FieldDescriptor::CPPTYPE_INT64: return "int64";
- case FieldDescriptor::CPPTYPE_UINT32: return "uint32";
- case FieldDescriptor::CPPTYPE_UINT64: return "uint64";
- case FieldDescriptor::CPPTYPE_DOUBLE: return "double";
- case FieldDescriptor::CPPTYPE_FLOAT: return "float";
- case FieldDescriptor::CPPTYPE_BOOL: return "bool";
- case FieldDescriptor::CPPTYPE_ENUM: return "enum";
- case FieldDescriptor::CPPTYPE_STRING: return "string";
- case FieldDescriptor::CPPTYPE_MESSAGE: return "message";
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_INT32: return "int32";
+ case FieldDescriptor::TYPE_INT64: return "int64";
+ case FieldDescriptor::TYPE_UINT32: return "uint32";
+ case FieldDescriptor::TYPE_UINT64: return "uint64";
+ case FieldDescriptor::TYPE_SINT32: return "sint32";
+ case FieldDescriptor::TYPE_SINT64: return "sint64";
+ case FieldDescriptor::TYPE_FIXED32: return "fixed32";
+ case FieldDescriptor::TYPE_FIXED64: return "fixed64";
+ case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
+ case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
+ case FieldDescriptor::TYPE_DOUBLE: return "double";
+ case FieldDescriptor::TYPE_FLOAT: return "float";
+ case FieldDescriptor::TYPE_BOOL: return "bool";
+ case FieldDescriptor::TYPE_ENUM: return "enum";
+ case FieldDescriptor::TYPE_STRING: return "string";
+ case FieldDescriptor::TYPE_BYTES: return "bytes";
+ case FieldDescriptor::TYPE_MESSAGE: return "message";
+ case FieldDescriptor::TYPE_GROUP: return "group";
default: assert(false); return "";
}
}
-void GenerateMessage(const google::protobuf::Descriptor* message,
- google::protobuf::io::Printer* printer) {
- printer->Print(
- "add_message \"$name$\" do\n",
- "name", message->full_name());
- printer->Indent();
+void GenerateField(const google::protobuf::FieldDescriptor* field,
+ google::protobuf::io::Printer* printer) {
+
+ if (field->is_map()) {
+ const FieldDescriptor* key_field =
+ field->message_type()->FindFieldByNumber(1);
+ const FieldDescriptor* value_field =
+ field->message_type()->FindFieldByNumber(2);
+
+ printer->Print(
+ "map :$name$, :$key_type$, :$value_type$, $number$",
+ "name", field->name(),
+ "key_type", TypeName(key_field),
+ "value_type", TypeName(value_field),
+ "number", IntToString(field->number()));
+
+ if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ ", \"$subtype$\"\n",
+ "subtype", value_field->message_type()->full_name());
+ } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ printer->Print(
+ ", \"$subtype$\"\n",
+ "subtype", value_field->enum_type()->full_name());
+ } else {
+ printer->Print("\n");
+ }
+ } else {
- for (int i = 0; i < message->field_count(); i++) {
- const FieldDescriptor* field = message->field(i);
printer->Print(
"$label$ :$name$, ",
"label", LabelForField(field),
@@ -117,6 +145,7 @@ void GenerateMessage(const google::protobuf::Descriptor* message,
":$type$, $number$",
"type", TypeName(field),
"number", IntToString(field->number()));
+
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
", \"$subtype$\"\n",
@@ -129,6 +158,49 @@ void GenerateMessage(const google::protobuf::Descriptor* message,
printer->Print("\n");
}
}
+}
+
+void GenerateOneof(const google::protobuf::OneofDescriptor* oneof,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "oneof :$name$ do\n",
+ "name", oneof->name());
+ printer->Indent();
+
+ for (int i = 0; i < oneof->field_count(); i++) {
+ const FieldDescriptor* field = oneof->field(i);
+ GenerateField(field, printer);
+ }
+
+ printer->Outdent();
+ printer->Print("end\n");
+}
+
+void GenerateMessage(const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer) {
+
+ // Don't generate MapEntry messages -- we use the Ruby extension's native
+ // support for map fields instead.
+ if (message->options().map_entry()) {
+ return;
+ }
+
+ printer->Print(
+ "add_message \"$name$\" do\n",
+ "name", message->full_name());
+ printer->Indent();
+
+ for (int i = 0; i < message->field_count(); i++) {
+ const FieldDescriptor* field = message->field(i);
+ if (!field->containing_oneof()) {
+ GenerateField(field, printer);
+ }
+ }
+
+ for (int i = 0; i < message->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = message->oneof_decl(i);
+ GenerateOneof(oneof, printer);
+ }
printer->Outdent();
printer->Print("end\n");
@@ -185,6 +257,13 @@ void GenerateMessageAssignment(
const std::string& prefix,
const google::protobuf::Descriptor* message,
google::protobuf::io::Printer* printer) {
+
+ // Don't generate MapEntry messages -- we use the Ruby extension's native
+ // support for map fields instead.
+ if (message->options().map_entry()) {
+ return;
+ }
+
printer->Print(
"$prefix$$name$ = ",
"prefix", prefix,
@@ -307,7 +386,8 @@ bool Generator::Generate(
std::string filename =
StripDotProto(file->name()) + ".rb";
- scoped_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(filename));
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(filename));
io::Printer printer(output.get(), '$');
GenerateFile(file, &printer);
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.h b/src/google/protobuf/compiler/ruby/ruby_generator.h
index 48dbefd1..75555c31 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.h
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.h
@@ -40,7 +40,8 @@ namespace protobuf {
namespace compiler {
namespace ruby {
-class Generator : public google::protobuf::compiler::CodeGenerator {
+class LIBPROTOC_EXPORT Generator
+ : public google::protobuf::compiler::CodeGenerator {
virtual bool Generate(
const FileDescriptor* file,
const string& parameter,
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
new file mode 100644
index 00000000..1b04cb32
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -0,0 +1,123 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <memory>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+namespace {
+
+string FindRubyTestDir(const string& file) {
+ // Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
+#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+ string prefix = ".";
+ while (!File::Exists(prefix + "/src/google/protobuf/compiler/ruby" + file)) {
+ if (!File::Exists(prefix)) {
+ GOOGLE_LOG(FATAL)
+ << "Could not find Ruby test directory. Please run tests from "
+ "somewhere within the protobuf source package.";
+ }
+ prefix += "/..";
+ }
+ return prefix + "/src/google/protobuf/compiler/ruby";
+#else
+ return "third_party/protobuf/src/google/protobuf/compiler/ruby";
+#endif // GOOGLE_THIRD_PARTY_PROTOBUF
+}
+
+// This test is a simple golden-file test over the output of the Ruby code
+// generator. When we make changes to the Ruby extension and alter the Ruby code
+// generator to use those changes, we should (i) manually test the output of the
+// code generator with the extension, and (ii) update the golden output above.
+// Some day, we may integrate build systems between protoc and the language
+// extensions to the point where we can do this test in a more automated way.
+
+TEST(RubyGeneratorTest, GeneratorTest) {
+ string ruby_tests = FindRubyTestDir("/ruby_generated_code.proto");
+
+ google::protobuf::compiler::CommandLineInterface cli;
+ cli.SetInputsAreProtoPathRelative(true);
+
+ ruby::Generator ruby_generator;
+ cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+
+ // Copy generated_code.proto to the temporary test directory.
+ string test_input;
+ GOOGLE_CHECK_OK(File::GetContents(
+ ruby_tests + "/ruby_generated_code.proto",
+ &test_input,
+ true));
+ GOOGLE_CHECK_OK(File::SetContents(
+ TestTempDir() + "/ruby_generated_code.proto",
+ test_input,
+ true));
+
+ // Invoke the proto compiler (we will be inside TestTempDir() at this point).
+ string ruby_out = "--ruby_out=" + TestTempDir();
+ string proto_path = "--proto_path=" + TestTempDir();
+ const char* argv[] = {
+ "protoc",
+ ruby_out.c_str(),
+ proto_path.c_str(),
+ "ruby_generated_code.proto",
+ };
+
+ EXPECT_EQ(0, cli.Run(4, argv));
+
+ // Load the generated output and compare to the expected result.
+ string output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ TestTempDir() + "/ruby_generated_code.rb",
+ &output,
+ true));
+ string expected_output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ ruby_tests + "/ruby_generated_code.rb",
+ &expected_output,
+ true));
+ EXPECT_EQ(expected_output, output);
+}
+
+} // namespace
+} // namespace ruby
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 61ae4381..a3cff1f8 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -171,7 +171,7 @@ bool Subprocess::Communicate(const Message& input, Message* output,
DWORD wait_result =
WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
- HANDLE signaled_handle;
+ HANDLE signaled_handle = NULL;
if (wait_result >= WAIT_OBJECT_0 &&
wait_result < WAIT_OBJECT_0 + handle_count) {
signaled_handle = handles[wait_result - WAIT_OBJECT_0];