aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/compiler')
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc2
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc69
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc38
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc25
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h7
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc3
-rw-r--r--src/google/protobuf/compiler/cpp/metadata_test.cc183
-rw-r--r--src/google/protobuf/compiler/java/java_context.cc9
-rw-r--r--src/google/protobuf/compiler/java/java_context.h16
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc17
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc29
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field_lite.cc19
-rw-r--r--src/google/protobuf/compiler/java/java_enum_lite.cc10
-rw-r--r--src/google/protobuf/compiler/java/java_extension.cc87
-rw-r--r--src/google/protobuf/compiler/java/java_extension_lite.cc118
-rw-r--r--src/google/protobuf/compiler/java/java_extension_lite.h76
-rw-r--r--src/google/protobuf/compiler/java/java_field.cc12
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc35
-rw-r--r--src/google/protobuf/compiler/java/java_file.h3
-rw-r--r--src/google/protobuf/compiler/java/java_generator.cc16
-rw-r--r--src/google/protobuf/compiler/java/java_generator_factory.cc14
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.h39
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc5
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.cc28
-rw-r--r--src/google/protobuf/compiler/java/java_map_field_lite.cc9
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc175
-rw-r--r--src/google/protobuf/compiler/java/java_message.h10
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder.cc11
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder_lite.cc19
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc3
-rw-r--r--src/google/protobuf/compiler/java/java_message_field_lite.cc3
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.cc170
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.h3
-rw-r--r--src/google/protobuf/compiler/java/java_name_resolver.cc7
-rw-r--r--src/google/protobuf/compiler/java/java_name_resolver.h1
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc12
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field_lite.cc5
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.cc7
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.h5
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.cc30
-rw-r--r--src/google/protobuf/compiler/java/java_string_field_lite.cc19
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc7
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.cc8
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.cc777
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.h18
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.cc12
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.h5
-rw-r--r--src/google/protobuf/compiler/plugin.cc81
-rw-r--r--src/google/protobuf/compiler/plugin.h18
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc4
-rw-r--r--src/google/protobuf/compiler/subprocess.cc2
56 files changed, 1596 insertions, 727 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 3a816b05..87843f62 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -49,7 +49,7 @@
#include <iostream>
#include <ctype.h>
-#ifdef GOOGLE_PROTOBUF_ARCH_SPARC
+#ifdef GOOGLE_PROTOBUF_ARCH_SPARC
#include <limits.h> //For PATH_MAX
#endif
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index dda007d4..e3dd2295 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -63,13 +63,13 @@
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-namespace google {
-namespace protobuf {
-namespace compiler {
// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
// which case tcmalloc will print warnings that fail the plugin tests.
#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+namespace google {
+namespace protobuf {
+namespace compiler {
#if defined(_WIN32)
#ifndef STDIN_FILENO
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 5ee6f000..415ae60f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -69,11 +69,12 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
EnumGenerator::~EnumGenerator() {}
-void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) {
+void EnumGenerator::FillForwardDeclaration(
+ map<string, const EnumDescriptor*>* enum_names) {
if (!options_.proto_h) {
return;
}
- enum_names->insert(classname_);
+ (*enum_names)[classname_] = descriptor_;
}
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
@@ -83,6 +84,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
printer->Print(vars, "enum $enumbase$ {\n");
+ printer->Annotate("enumbase", descriptor_);
printer->Indent();
const EnumValueDescriptor* min_value = descriptor_->value(0);
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index f3aa72e4..61e40346 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -64,8 +64,10 @@ class EnumGenerator {
// Fills the name to use when declaring the enum. This is for use when
// generating other .proto.h files. This code should be placed within the
// enum's package namespace, but NOT within any class, even for nested
- // enums.
- void FillForwardDeclaration(set<string>* enum_names);
+ // enums. A given key in enum_names will map from an enum class name to the
+ // EnumDescriptor that was responsible for its inclusion in the map. This can
+ // be used to associate the descriptor with the code generated for it.
+ void FillForwardDeclaration(map<string, const EnumDescriptor*>* enum_names);
// Generate header code defining the enum. This code should be placed
// within the enum's package namespace, but NOT within any class, even for
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 37e4bae4..d48171b0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -94,7 +94,8 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
FileGenerator::~FileGenerator() {}
-void FileGenerator::GenerateProtoHeader(io::Printer* printer) {
+void FileGenerator::GenerateProtoHeader(io::Printer* printer,
+ const string& info_path) {
if (!options_.proto_h) {
return;
}
@@ -114,6 +115,8 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer) {
"dependency", dependency);
}
+ GenerateMetadataPragma(printer, info_path);
+
printer->Print(
"// @@protoc_insertion_point(includes)\n");
@@ -167,7 +170,8 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer) {
GenerateBottomHeaderGuard(printer, filename_identifier);
}
-void FileGenerator::GeneratePBHeader(io::Printer* printer) {
+void FileGenerator::GeneratePBHeader(io::Printer* printer,
+ const string& info_path) {
string filename_identifier =
FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : ""));
GenerateTopHeaderGuard(printer, filename_identifier);
@@ -179,6 +183,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) {
GenerateLibraryIncludes(printer);
}
GenerateDependencyIncludes(printer);
+ GenerateMetadataPragma(printer, info_path);
printer->Print(
"// @@protoc_insertion_point(includes)\n");
@@ -237,7 +242,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) {
}
void FileGenerator::GenerateSource(io::Printer* printer) {
- bool well_known = IsWellKnownMessage(file_);
+ const bool use_system_include = IsWellKnownMessage(file_);
string header =
StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
printer->Print(
@@ -258,8 +263,8 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"#include <google/protobuf/wire_format_lite_inl.h>\n",
"filename", file_->name(),
"header", header,
- "left", well_known ? "<" : "\"",
- "right", well_known ? ">" : "\"");
+ "left", use_system_include ? "<" : "\"",
+ "right", use_system_include ? ">" : "\"");
// Unknown fields implementation in lite mode uses StringOutputStream
if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
@@ -401,20 +406,24 @@ class FileGenerator::ForwardDeclarations {
return ns;
}
- set<string>& classes() { return classes_; }
- set<string>& enums() { return enums_; }
+ map<string, const Descriptor*>& classes() { return classes_; }
+ map<string, const EnumDescriptor*>& enums() { return enums_; }
void Print(io::Printer* printer) const {
- for (set<string>::const_iterator it = enums_.begin(), end = enums_.end();
+ for (map<string, const EnumDescriptor *>::const_iterator
+ it = enums_.begin(),
+ end = enums_.end();
it != end; ++it) {
- printer->Print("enum $enumname$ : int;\n"
- "bool $enumname$_IsValid(int value);\n",
- "enumname", it->c_str());
+ printer->Print("enum $enumname$ : int;\n", "enumname", it->first);
+ printer->Annotate("enumname", it->second);
+ printer->Print("bool $enumname$_IsValid(int value);\n", "enumname",
+ it->first);
}
- for (set<string>::const_iterator it = classes_.begin(),
- end = classes_.end();
+ for (map<string, const Descriptor *>::const_iterator it = classes_.begin(),
+ end = classes_.end();
it != end; ++it) {
- printer->Print("class $classname$;\n", "classname", it->c_str());
+ printer->Print("class $classname$;\n", "classname", it->first);
+ printer->Annotate("classname", it->second);
}
for (map<string, ForwardDeclarations *>::const_iterator
it = namespaces_.begin(),
@@ -431,8 +440,8 @@ class FileGenerator::ForwardDeclarations {
private:
map<string, ForwardDeclarations*> namespaces_;
- set<string> classes_;
- set<string> enums_;
+ map<string, const Descriptor*> classes_;
+ map<string, const EnumDescriptor*> enums_;
};
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
@@ -854,6 +863,19 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
}
}
+void FileGenerator::GenerateMetadataPragma(io::Printer* printer,
+ const string& info_path) {
+ if (!info_path.empty() && !options_.annotation_pragma_name.empty() &&
+ !options_.annotation_guard_name.empty()) {
+ printer->Print(
+ "#ifdef $guard$\n"
+ "#pragma $pragma$ \"$info_path$\"\n"
+ "#endif // $guard$\n",
+ "guard", options_.annotation_guard_name, "pragma",
+ options_.annotation_pragma_name, "info_path", info_path);
+ }
+}
+
void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
set<string> public_import_names;
for (int i = 0; i < file_->public_dependency_count(); i++) {
@@ -861,16 +883,17 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
}
for (int i = 0; i < file_->dependency_count(); i++) {
- bool well_known = IsWellKnownMessage(file_->dependency(i));
+ const bool use_system_include = IsWellKnownMessage(file_->dependency(i));
const string& name = file_->dependency(i)->name();
bool public_import = (public_import_names.count(name) != 0);
+
printer->Print(
"#include $left$$dependency$.pb.h$right$$iwyu$\n",
"dependency", StripProto(name),
"iwyu", (public_import) ? " // IWYU pragma: export" : "",
- "left", well_known ? "<" : "\"",
- "right", well_known ? ">" : "\"");
+ "left", use_system_include ? "<" : "\"",
+ "right", use_system_include ? ">" : "\"");
}
}
@@ -897,13 +920,15 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations(
}
void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
- set<string> classes;
+ map<string, const Descriptor*> classes;
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->FillMessageForwardDeclarations(&classes);
}
- for (set<string>::const_iterator it = classes.begin(), end = classes.end();
+ for (map<string, const Descriptor *>::const_iterator it = classes.begin(),
+ end = classes.end();
it != end; ++it) {
- printer->Print("class $classname$;\n", "classname", it->c_str());
+ printer->Print("class $classname$;\n", "classname", it->first);
+ printer->Annotate("classname", it->second);
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 29cdaea5..ebe990c2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -69,8 +69,14 @@ class FileGenerator {
const Options& options);
~FileGenerator();
- void GenerateProtoHeader(io::Printer* printer);
- void GeneratePBHeader(io::Printer* printer);
+ // info_path, if non-empty, should be the path (relative to printer's output)
+ // to the metadata file describing this proto header.
+ void GenerateProtoHeader(io::Printer* printer,
+ const string& info_path);
+ // info_path, if non-empty, should be the path (relative to printer's output)
+ // to the metadata file describing this PB header.
+ void GeneratePBHeader(io::Printer* printer,
+ const string& info_path);
void GenerateSource(io::Printer* printer);
private:
@@ -102,6 +108,10 @@ class FileGenerator {
void GenerateLibraryIncludes(io::Printer* printer);
void GenerateDependencyIncludes(io::Printer* printer);
+ // Generate a pragma to pull in metadata using the given info_path (if
+ // non-empty). info_path should be relative to printer's output.
+ void GenerateMetadataPragma(io::Printer* printer, const string& info_path);
+
// Generates a couple of different pieces before definitions:
void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 781526b5..c7aec93a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -90,6 +90,12 @@ bool CppGenerator::Generate(const FileDescriptor* file,
file_options.dllexport_decl = options[i].second;
} else if (options[i].first == "safe_boundary_check") {
file_options.safe_boundary_check = true;
+ } else if (options[i].first == "annotate_headers") {
+ file_options.annotate_headers = true;
+ } else if (options[i].first == "annotation_pragma_name") {
+ file_options.annotation_pragma_name = options[i].second;
+ } else if (options[i].first == "annotation_guard_name") {
+ file_options.annotation_guard_name = options[i].second;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
@@ -107,16 +113,40 @@ bool CppGenerator::Generate(const FileDescriptor* file,
if (file_options.proto_h) {
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".proto.h"));
- io::Printer printer(output.get(), '$');
- file_generator.GenerateProtoHeader(&printer);
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ string info_path = basename + ".proto.h.meta";
+ io::Printer printer(output.get(), '$', file_options.annotate_headers
+ ? &annotation_collector
+ : NULL);
+ file_generator.GenerateProtoHeader(
+ &printer, file_options.annotate_headers ? info_path : "");
+ if (file_options.annotate_headers) {
+ scoped_ptr<io::ZeroCopyOutputStream> info_output(
+ generator_context->Open(info_path));
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ }
}
basename.append(".pb");
{
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".h"));
- io::Printer printer(output.get(), '$');
- file_generator.GeneratePBHeader(&printer);
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ string info_path = basename + ".h.meta";
+ io::Printer printer(output.get(), '$', file_options.annotate_headers
+ ? &annotation_collector
+ : NULL);
+ file_generator.GeneratePBHeader(
+ &printer, file_options.annotate_headers ? info_path : "");
+ if (file_options.annotate_headers) {
+ scoped_ptr<io::ZeroCopyOutputStream> info_output(
+ generator_context->Open(info_path));
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ }
}
// Generate cc file.
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 8304ebbd..c3166611 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -423,8 +423,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
MessageGenerator::~MessageGenerator() {}
void MessageGenerator::
-FillMessageForwardDeclarations(set<string>* class_names) {
- class_names->insert(classname_);
+FillMessageForwardDeclarations(map<string, const Descriptor*>* class_names) {
+ (*class_names)[classname_] = descriptor_;
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// map entry message doesn't need forward declaration. Since map entry
@@ -436,7 +436,7 @@ FillMessageForwardDeclarations(set<string>* class_names) {
}
void MessageGenerator::
-FillEnumForwardDeclarations(set<string>* enum_names) {
+FillEnumForwardDeclarations(map<string, const EnumDescriptor*>* enum_names) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->FillEnumForwardDeclarations(enum_names);
}
@@ -892,6 +892,7 @@ GenerateClassDefinition(io::Printer* printer) {
}
printer->Print(vars,
"class $dllexport$$classname$ : public $superclass$ {\n");
+ printer->Annotate("classname", descriptor_);
if (use_dependent_base_) {
printer->Print(vars, " friend class $superclass$;\n");
}
@@ -1027,6 +1028,8 @@ GenerateClassDefinition(io::Printer* printer) {
"// implements Any -----------------------------------------------\n"
"\n"
"void PackFrom(const ::google::protobuf::Message& message);\n"
+ "void PackFrom(const ::google::protobuf::Message& message,\n"
+ " const ::std::string& type_url_prefix);\n"
"bool UnpackTo(::google::protobuf::Message* message) const;\n"
"template<typename T> bool Is() const {\n"
" return _any_metadata_.Is<T>();\n"
@@ -1789,6 +1792,11 @@ GenerateClassMethods(io::Printer* printer) {
" _any_metadata_.PackFrom(message);\n"
"}\n"
"\n"
+ "void $classname$::PackFrom(const ::google::protobuf::Message& message,\n"
+ " const ::std::string& type_url_prefix) {\n"
+ " _any_metadata_.PackFrom(message, type_url_prefix);\n"
+ "}\n"
+ "\n"
"bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
" return _any_metadata_.UnpackTo(message);\n"
"}\n"
@@ -1899,11 +1907,10 @@ GenerateClassMethods(io::Printer* printer) {
void MessageGenerator::
GenerateOffsets(io::Printer* printer) {
- printer->Print(
- "static const int $classname$_offsets_[$field_count$] = {\n",
- "classname", classname_,
- "field_count", SimpleItoa(max(
- 1, descriptor_->field_count() + descriptor_->oneof_decl_count())));
+ printer->Print("static const int $classname$_offsets_[$field_count$] = {\n",
+ "classname", classname_, "field_count",
+ SimpleItoa(std::max(1, descriptor_->field_count() +
+ descriptor_->oneof_decl_count())));
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -2907,7 +2914,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// on the CodedOutputStream.
printer->Print(
" ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
- " ::google::protobuf::internal::NewPermanentCallback(\n"
+ " google::protobuf::internal::NewPermanentCallback(\n"
" &MutableUnknownFieldsFor$classname$, this));\n"
" ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
" &unknown_fields_string, false);\n",
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 8e19a3f0..31223e13 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -67,9 +67,13 @@ class MessageGenerator {
// Header stuff.
// Return names for foward declarations of this class and all its nested
- // types.
- void FillMessageForwardDeclarations(set<string>* class_names);
- void FillEnumForwardDeclarations(set<string>* enum_names);
+ // types. A given key in {class,enum}_names will map from a class name to the
+ // descriptor that was responsible for its inclusion in the map. This can be
+ // used to associate the descriptor with the code generated for it.
+ void FillMessageForwardDeclarations(
+ map<string, const Descriptor*>* class_names);
+ void FillEnumForwardDeclarations(
+ map<string, const EnumDescriptor*>* enum_names);
// Generate definitions of all nested enums (must come before class
// definitions because those classes use the enums definitions).
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 4463f200..e908362b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -43,11 +43,14 @@ namespace cpp {
// Generator options (see generator.cc for a description of each):
struct Options {
- Options() : safe_boundary_check(false), proto_h(false) {
- }
+ Options()
+ : safe_boundary_check(false), proto_h(false), annotate_headers(false) {}
string dllexport_decl;
bool safe_boundary_check;
bool proto_h;
+ bool annotate_headers;
+ string annotation_pragma_name;
+ string annotation_guard_name;
};
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 9942a343..148da883 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -82,7 +82,6 @@
namespace google {
namespace protobuf {
-using internal::NewPermanentCallback;
namespace compiler {
namespace cpp {
@@ -1253,7 +1252,7 @@ class GeneratedServiceTest : public testing::Test {
foo_(descriptor_->FindMethodByName("Foo")),
bar_(descriptor_->FindMethodByName("Bar")),
stub_(&mock_channel_),
- done_(NewPermanentCallback(&DoNothing)) {}
+ done_(google::protobuf::internal::NewPermanentCallback(&DoNothing)) {}
virtual void SetUp() {
ASSERT_TRUE(foo_ != NULL);
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index 422eb73b..61dc283a 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -51,6 +51,189 @@ namespace compiler {
namespace cpp {
namespace {
+// A CodeGenerator that captures the FileDescriptor it's passed as a
+// FileDescriptorProto.
+class DescriptorCapturingGenerator : public CodeGenerator {
+ public:
+ // Does not own file; file must outlive the Generator.
+ explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
+ : file_(file) {}
+
+ virtual bool Generate(const FileDescriptor* file, const string& parameter,
+ GeneratorContext* context, string* error) const {
+ file->CopyTo(file_);
+ return true;
+ }
+
+ private:
+ FileDescriptorProto* file_;
+};
+
+class CppMetadataTest : public ::testing::Test {
+ public:
+ // Adds a file with name `filename` and content `data`.
+ void AddFile(const string& filename, const string& data) {
+ GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data,
+ true));
+ }
+
+ // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
+ // code from the previously added file with name `filename`. Returns true on
+ // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to
+ // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info.
+ bool CaptureMetadata(const string& filename, FileDescriptorProto* file,
+ string* pb_h, GeneratedCodeInfo* pb_h_info,
+ string* proto_h, GeneratedCodeInfo* proto_h_info,
+ string* pb_cc) {
+ google::protobuf::compiler::CommandLineInterface cli;
+ cli.SetInputsAreProtoPathRelative(true);
+
+ CppGenerator cpp_generator;
+ DescriptorCapturingGenerator capturing_generator(file);
+ cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
+ cli.RegisterGenerator("--capture_out", &capturing_generator, "");
+
+ string proto_path = "-I" + TestTempDir();
+ string cpp_out =
+ "--cpp_out=annotate_headers=true,"
+ "annotation_pragma_name=pragma_name,"
+ "annotation_guard_name=guard_name:" +
+ TestTempDir();
+ string capture_out = "--capture_out=" + TestTempDir();
+
+ const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(),
+ capture_out.c_str(), filename.c_str()};
+
+ if (cli.Run(5, argv) != 0) {
+ return false;
+ }
+
+ string output_base = TestTempDir() + "/" + StripProto(filename);
+
+ if (pb_cc != NULL) {
+ GOOGLE_CHECK_OK(
+ File::GetContents(output_base + ".pb.cc", pb_cc, true));
+ }
+
+ if (pb_h != NULL && pb_h_info != NULL) {
+ GOOGLE_CHECK_OK(
+ File::GetContents(output_base + ".pb.h", pb_h, true));
+ if (!DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
+ return false;
+ }
+ }
+
+ if (proto_h != NULL && proto_h_info != NULL) {
+ GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
+ true));
+ if (!DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ // Decodes GeneratedCodeInfo stored in path and copies it to info.
+ // Returns true on success.
+ bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) {
+ string data;
+ GOOGLE_CHECK_OK(File::GetContents(path, &data, true));
+ io::ArrayInputStream input(data.data(), data.size());
+ return info->ParseFromZeroCopyStream(&input);
+ }
+};
+
+const char kSmallTestFile[] =
+ "syntax = \"proto2\";\n"
+ "package foo;\n"
+ "enum Enum { VALUE = 0; }\n"
+ "message Message { }\n";
+
+// Finds the Annotation for a given source file and path (or returns null if it
+// couldn't).
+const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
+ const GeneratedCodeInfo& info, const string& source_file,
+ const vector<int>& path) {
+ for (int i = 0; i < info.annotation_size(); ++i) {
+ const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i);
+ if (annotation->source_file() != source_file ||
+ annotation->path_size() != path.size()) {
+ continue;
+ }
+ int node = 0;
+ for (; node < path.size(); ++node) {
+ if (annotation->path(node) != path[node]) {
+ break;
+ }
+ }
+ if (node == path.size()) {
+ return annotation;
+ }
+ }
+ return NULL;
+}
+
+// Returns true if the provided annotation covers a given substring in
+// file_content.
+bool AnnotationMatchesSubstring(const string& file_content,
+ const GeneratedCodeInfo::Annotation* annotation,
+ const string& expected_text) {
+ uint32 begin = annotation->begin();
+ uint32 end = annotation->end();
+ if (end < begin || end > file_content.size()) {
+ return false;
+ }
+ return file_content.substr(begin, end - begin) == expected_text;
+}
+
+TEST_F(CppMetadataTest, CapturesEnumNames) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ string pb_h;
+ AddFile("test.proto", kSmallTestFile);
+ EXPECT_TRUE(
+ CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+ EXPECT_EQ("Enum", file.enum_type(0).name());
+ vector<int> enum_path;
+ enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+ enum_path.push_back(0);
+ const GeneratedCodeInfo::Annotation* enum_annotation =
+ FindAnnotationOnPath(info, "test.proto", enum_path);
+ EXPECT_TRUE(NULL != enum_annotation);
+ EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
+}
+
+TEST_F(CppMetadataTest, AddsPragma) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ string pb_h;
+ AddFile("test.proto", kSmallTestFile);
+ EXPECT_TRUE(
+ CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+ EXPECT_TRUE(pb_h.find("#ifdef guard_name") != string::npos);
+ EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
+ string::npos);
+}
+
+TEST_F(CppMetadataTest, CapturesMessageNames) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ string pb_h;
+ AddFile("test.proto", kSmallTestFile);
+ EXPECT_TRUE(
+ CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ vector<int> message_path;
+ message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+ message_path.push_back(0);
+ const GeneratedCodeInfo::Annotation* message_annotation =
+ FindAnnotationOnPath(info, "test.proto", message_path);
+ EXPECT_TRUE(NULL != message_annotation);
+ EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
+}
+
} // namespace
} // namespace cpp
} // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
index 7d21fe61..0a112888 100644
--- a/src/google/protobuf/compiler/java/java_context.cc
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -43,7 +43,7 @@ namespace compiler {
namespace java {
Context::Context(const FileDescriptor* file)
- : name_resolver_(new ClassNameResolver) {
+ : name_resolver_(new ClassNameResolver), enforce_lite_(false) {
InitializeFieldGeneratorInfo(file);
}
@@ -189,6 +189,13 @@ const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
return result;
}
+// Does this message class have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
+ return enforce_lite_ || descriptor->file()->options().optimize_for() !=
+ FileOptions::CODE_SIZE;
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h
index 5b595d07..a480e45d 100644
--- a/src/google/protobuf/compiler/java/java_context.h
+++ b/src/google/protobuf/compiler/java/java_context.h
@@ -46,6 +46,7 @@ namespace protobuf {
class FieldDescriptor;
class OneofDescriptor;
class Descriptor;
+ class EnumDescriptor;
namespace compiler {
namespace java {
class ClassNameResolver; // name_resolver.h
@@ -78,6 +79,20 @@ class Context {
const OneofGeneratorInfo* GetOneofGeneratorInfo(
const OneofDescriptor* oneof) const;
+ // Enforces all the files (including transitive dependencies) to use
+ // LiteRuntime.
+ void SetEnforceLite(bool enforce_lite) {
+ enforce_lite_ = enforce_lite;
+ }
+
+ bool EnforceLite() const {
+ return enforce_lite_;
+ }
+
+ // Does this message class have generated parsing, serialization, and other
+ // standard methods for which reflection-based fallback implementations exist?
+ bool HasGeneratedMethods(const Descriptor* descriptor) const;
+
private:
void InitializeFieldGeneratorInfo(const FileDescriptor* file);
void InitializeFieldGeneratorInfoForMessage(const Descriptor* message);
@@ -87,6 +102,7 @@ class Context {
google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_;
map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_;
+ bool enforce_lite_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
};
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 5fc9b002..9eea873a 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -64,6 +64,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
bool immutable_api,
Context* context)
: descriptor_(descriptor), immutable_api_(immutable_api),
+ context_(context),
name_resolver_(context->GetNameResolver()) {
for (int i = 0; i < descriptor_->value_count(); i++) {
const EnumValueDescriptor* value = descriptor_->value(i);
@@ -150,7 +151,15 @@ void EnumGenerator::Generate(io::Printer* printer) {
" return value;\n"
"}\n"
"\n"
+ "/**\n"
+ " * @deprecated Use {@link #forNumber(int)} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public static $classname$ valueOf(int value) {\n"
+ " return forNumber(value);\n"
+ "}\n"
+ "\n"
+ "public static $classname$ forNumber(int value) {\n"
" switch (value) {\n",
"classname", descriptor_->name());
printer->Indent();
@@ -178,7 +187,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
" $classname$> internalValueMap =\n"
" new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
" public $classname$ findValueByNumber(int number) {\n"
- " return $classname$.valueOf(number);\n"
+ " return $classname$.forNumber(number);\n"
" }\n"
" };\n"
"\n",
@@ -187,7 +196,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
// -----------------------------------------------------------------
// Reflection
- if (HasDescriptorMethods(descriptor_)) {
+ if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
printer->Print(
"public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
" getValueDescriptor() {\n"
@@ -229,7 +238,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
" (com.google.protobuf.Descriptors.FileDescriptor)\n"
" m.invoke(immutableFileClass);\n"
" return file.getEnumTypes().get($index$);\n"
- "} catch (Exception e) {\n"
+ "} catch (java.lang.Exception e) {\n"
// Immutable classes cannot be found. Proceed as if custom options
// don't exist.
"}\n",
@@ -313,7 +322,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
"private final int value;\n\n"
"private $classname$(int index, int value) {\n",
"classname", descriptor_->name());
- if (HasDescriptorMethods(descriptor_)) {
+ if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
printer->Print(" this.index = index;\n");
}
printer->Print(
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 558da968..3e54be3d 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -68,21 +68,14 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
(*variables)["default_number"] = SimpleItoa(
descriptor->default_value_enum()->number());
- if (descriptor->is_packed()) {
- (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag(
- descriptor->number(),
- internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
- } else {
- (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
- }
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
(*variables)["tag_size"] = SimpleItoa(
internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+ (*variables)["on_changed"] = "onChanged();";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -198,7 +191,7 @@ GenerateMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
- " $type$ result = $type$.valueOf($name$_);\n"
+ " $type$ result = $type$.forNumber($name$_);\n"
" return result == null ? $unknown$ : result;\n"
"}\n");
}
@@ -231,7 +224,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
- " $type$ result = $type$.valueOf($name$_);\n"
+ " $type$ result = $type$.forNumber($name$_);\n"
" return result == null ? $unknown$ : result;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
@@ -311,7 +304,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n"
+ "$type$ value = $type$.forNumber(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -405,7 +398,7 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" if ($has_oneof_case_message$) {\n"
- " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+ " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" return $default$;\n"
@@ -443,7 +436,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" if ($has_oneof_case_message$) {\n"
- " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+ " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" return $default$;\n"
@@ -500,7 +493,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n"
+ "$type$ value = $type$.forNumber(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -613,7 +606,7 @@ GenerateMembers(io::Printer* printer) const {
" new com.google.protobuf.Internal.ListAdapter.Converter<\n"
" java.lang.Integer, $type$>() {\n"
" public $type$ convert(java.lang.Integer from) {\n"
- " $type$ result = $type$.valueOf(from);\n"
+ " $type$ result = $type$.forNumber(from);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" };\n");
@@ -649,7 +642,7 @@ GenerateMembers(io::Printer* printer) const {
}
if (descriptor_->is_packed() &&
- HasGeneratedMethods(descriptor_->containing_type())) {
+ context_->HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize;\n");
}
@@ -846,7 +839,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n"
+ "$type$ value = $type$.forNumber(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index e3e87c58..5b98637b 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -75,8 +75,6 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -179,7 +177,7 @@ GenerateMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
- " $type$ result = $type$.valueOf($name$_);\n"
+ " $type$ result = $type$.forNumber($name$_);\n"
" return result == null ? $unknown$ : result;\n"
"}\n");
@@ -228,7 +226,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
" copyOnWrite();\n"
- " instance.set$capitalized_name$Value(int value);\n"
+ " instance.set$capitalized_name$Value(value);\n"
" return this;\n"
"}\n");
}
@@ -295,7 +293,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n"
+ "$type$ value = $type$.forNumber(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -389,7 +387,7 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" if ($has_oneof_case_message$) {\n"
- " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+ " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" return $default$;\n"
@@ -488,7 +486,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n"
+ "$type$ value = $type$.forNumber(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -602,7 +600,7 @@ GenerateMembers(io::Printer* printer) const {
" new com.google.protobuf.Internal.ListAdapter.Converter<\n"
" java.lang.Integer, $type$>() {\n"
" public $type$ convert(java.lang.Integer from) {\n"
- " $type$ result = $type$.valueOf(from);\n"
+ " $type$ result = $type$.forNumber(from);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" };\n");
@@ -638,7 +636,7 @@ GenerateMembers(io::Printer* printer) const {
}
if (descriptor_->options().packed() &&
- HasGeneratedMethods(descriptor_->containing_type())) {
+ context_->HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize;\n");
}
@@ -821,7 +819,6 @@ GenerateMergingCode(io::Printer* printer) const {
" ensure$capitalized_name$IsMutable();\n"
" $name$_.addAll(other.$name$_);\n"
" }\n"
- " $on_changed$\n"
"}\n");
}
@@ -844,7 +841,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n"
+ "$type$ value = $type$.forNumber(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index ed415eee..c22da8d7 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -141,7 +141,15 @@ void EnumLiteGenerator::Generate(io::Printer* printer) {
" return value;\n"
"}\n"
"\n"
+ "/**\n"
+ " * @deprecated Use {@link #forNumber(int)} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public static $classname$ valueOf(int value) {\n"
+ " return forNumber(value);\n"
+ "}\n"
+ "\n"
+ "public static $classname$ forNumber(int value) {\n"
" switch (value) {\n",
"classname", descriptor_->name());
printer->Indent();
@@ -169,7 +177,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) {
" $classname$> internalValueMap =\n"
" new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
" public $classname$ findValueByNumber(int number) {\n"
- " return $classname$.valueOf(number);\n"
+ " return $classname$.forNumber(number);\n"
" }\n"
" };\n"
"\n",
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 4db7085e..46b5faaa 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -118,75 +118,38 @@ void ImmutableExtensionGenerator::Generate(io::Printer* printer) {
"public static final int $constant_name$ = $number$;\n");
WriteFieldDocComment(printer, descriptor_);
- if (HasDescriptorMethods(descriptor_->file())) {
- // Non-lite extensions
- if (descriptor_->extension_scope() == NULL) {
- // Non-nested
- printer->Print(
- vars,
- "public static final\n"
- " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
- " $containing_type$,\n"
- " $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
- " .newFileScopedGeneratedExtension(\n"
- " $singular_type$.class,\n"
- " $prototype$);\n");
- } else {
- // Nested
- printer->Print(
- vars,
- "public static final\n"
- " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
- " $containing_type$,\n"
- " $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
- " .newMessageScopedGeneratedExtension(\n"
- " $scope$.getDefaultInstance(),\n"
- " $index$,\n"
- " $singular_type$.class,\n"
- " $prototype$);\n");
- }
+ if (descriptor_->extension_scope() == NULL) {
+ // Non-nested
+ printer->Print(
+ vars,
+ "public static final\n"
+ " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+ " $containing_type$,\n"
+ " $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+ " .newFileScopedGeneratedExtension(\n"
+ " $singular_type$.class,\n"
+ " $prototype$);\n");
} else {
- // Lite extensions
- if (descriptor_->is_repeated()) {
- printer->Print(
- vars,
- "public static final\n"
- " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
- " $containing_type$,\n"
- " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
- " .newRepeatedGeneratedExtension(\n"
- " $containing_type$.getDefaultInstance(),\n"
- " $prototype$,\n"
- " $enum_map$,\n"
- " $number$,\n"
- " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
- " $packed$,\n"
- " $singular_type$.class);\n");
- } else {
- printer->Print(
- vars,
- "public static final\n"
- " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
- " $containing_type$,\n"
- " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
- " .newSingularGeneratedExtension(\n"
- " $containing_type$.getDefaultInstance(),\n"
- " $default$,\n"
- " $prototype$,\n"
- " $enum_map$,\n"
- " $number$,\n"
- " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
- " $singular_type$.class);\n");
- }
+ // Nested
+ printer->Print(
+ vars,
+ "public static final\n"
+ " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+ " $containing_type$,\n"
+ " $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+ " .newMessageScopedGeneratedExtension(\n"
+ " $scope$.getDefaultInstance(),\n"
+ " $index$,\n"
+ " $singular_type$.class,\n"
+ " $prototype$);\n");
}
}
int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
io::Printer* printer) {
int bytecode_estimate = 0;
- if (descriptor_->extension_scope() == NULL &&
- HasDescriptorMethods(descriptor_->file())) {
- // Only applies to non-nested, non-lite extensions.
+ if (descriptor_->extension_scope() == NULL) {
+ // Only applies to non-nested extensions.
printer->Print(
"$name$.internalInit(descriptor.getExtensions().get($index$));\n",
"name", UnderscoresToCamelCase(descriptor_),
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc
index e69de29b..23261bac 100644
--- a/src/google/protobuf/compiler/java/java_extension_lite.cc
+++ b/src/google/protobuf/compiler/java/java_extension_lite.cc
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_extension_lite.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator(
+ const FieldDescriptor* descriptor, Context* context)
+ : descriptor_(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ if (descriptor_->extension_scope() != NULL) {
+ scope_ = name_resolver_->GetImmutableClassName(
+ descriptor_->extension_scope());
+ } else {
+ scope_ = name_resolver_->GetImmutableClassName(descriptor_->file());
+ }
+}
+
+ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {}
+
+void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) {
+ map<string, string> vars;
+ const bool kUseImmutableNames = true;
+ InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_,
+ &vars);
+ printer->Print(vars,
+ "public static final int $constant_name$ = $number$;\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ if (descriptor_->is_repeated()) {
+ printer->Print(
+ vars,
+ "public static final\n"
+ " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+ " $containing_type$,\n"
+ " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+ " .newRepeatedGeneratedExtension(\n"
+ " $containing_type$.getDefaultInstance(),\n"
+ " $prototype$,\n"
+ " $enum_map$,\n"
+ " $number$,\n"
+ " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+ " $packed$,\n"
+ " $singular_type$.class);\n");
+ } else {
+ printer->Print(
+ vars,
+ "public static final\n"
+ " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+ " $containing_type$,\n"
+ " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+ " .newSingularGeneratedExtension(\n"
+ " $containing_type$.getDefaultInstance(),\n"
+ " $default$,\n"
+ " $prototype$,\n"
+ " $enum_map$,\n"
+ " $number$,\n"
+ " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+ " $singular_type$.class);\n");
+ }
+}
+
+int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode(
+ io::Printer* printer) {
+ return 0;
+}
+
+int ImmutableExtensionLiteGenerator::GenerateRegistrationCode(
+ io::Printer* printer) {
+ printer->Print(
+ "registry.add($scope$.$name$);\n",
+ "scope", scope_,
+ "name", UnderscoresToCamelCase(descriptor_));
+ return 7;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h
index e69de29b..4cd49bda 100644
--- a/src/google/protobuf/compiler/java/java_extension_lite.h
+++ b/src/google/protobuf/compiler/java/java_extension_lite.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generates code for a lite extension, which may be within the scope of some
+// message or may be at file scope. This is much simpler than FieldGenerator
+// since extensions are just simple identifiers with interesting types.
+class ImmutableExtensionLiteGenerator : public ExtensionGenerator {
+ public:
+ explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor,
+ Context* context);
+ virtual ~ImmutableExtensionLiteGenerator();
+
+ virtual void Generate(io::Printer* printer);
+
+ // Returns an estimate of the number of bytes the printed code will compile to
+ virtual int GenerateNonNestedInitializationCode(io::Printer* printer);
+
+ // Returns an estimate of the number of bytes the printed code will compile to
+ virtual int GenerateRegistrationCode(io::Printer* printer);
+
+ private:
+ const FieldDescriptor* descriptor_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ string scope_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index c5434767..3c7bc5c4 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -77,7 +77,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator(
return new ImmutableMapFieldGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
- if (IsLazy(field)) {
+ if (IsLazy(field, context->EnforceLite())) {
return new RepeatedImmutableLazyMessageFieldGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
@@ -99,7 +99,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator(
if (field->containing_oneof()) {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
- if (IsLazy(field)) {
+ if (IsLazy(field, context->EnforceLite())) {
return new ImmutableLazyMessageOneofFieldGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
@@ -119,7 +119,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator(
} else {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
- if (IsLazy(field)) {
+ if (IsLazy(field, context->EnforceLite())) {
return new ImmutableLazyMessageFieldGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
@@ -150,7 +150,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
return new ImmutableMapFieldLiteGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
- if (IsLazy(field)) {
+ if (IsLazy(field, context->EnforceLite())) {
return new RepeatedImmutableLazyMessageFieldLiteGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
@@ -172,7 +172,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
if (field->containing_oneof()) {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
- if (IsLazy(field)) {
+ if (IsLazy(field, context->EnforceLite())) {
return new ImmutableLazyMessageOneofFieldLiteGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
@@ -192,7 +192,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
} else {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
- if (IsLazy(field)) {
+ if (IsLazy(field, context->EnforceLite())) {
return new ImmutableLazyMessageFieldLiteGenerator(
field, messageBitIndex, builderBitIndex, context);
} else {
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index c8172330..c53aae6b 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -177,7 +177,7 @@ void MaybeRestartJavaMethod(io::Printer* printer,
// since otherwise we hit a hardcoded limit in the jvm and javac will
// then fail with the error "code too large". This limit lets our
// estimates be off by a factor of two and still we're okay.
- static const int bytesPerMethod = 1<<15; // aka 32K
+ static const int bytesPerMethod = kMaxStaticSize;
if ((*bytecode_estimate) > bytesPerMethod) {
++(*method_num);
@@ -193,7 +193,8 @@ void MaybeRestartJavaMethod(io::Printer* printer,
} // namespace
-FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
+FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api,
+ bool enforce_lite)
: file_(file),
java_package_(FileJavaPackage(file, immutable_api)),
message_generators_(
@@ -204,6 +205,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
name_resolver_(context_->GetNameResolver()),
immutable_api_(immutable_api) {
classname_ = name_resolver_->GetFileClassName(file, immutable_api);
+ context_->SetEnforceLite(enforce_lite);
generator_factory_.reset(
new ImmutableGeneratorFactory(context_.get()));
for (int i = 0; i < file_->message_type_count(); ++i) {
@@ -262,7 +264,8 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Print(
"public static void registerAllExtensions(\n"
" com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
- "lite", HasDescriptorMethods(file_) ? "" : "Lite");
+ "lite",
+ HasDescriptorMethods(file_, context_->EnforceLite()) ? "" : "Lite");
printer->Indent();
@@ -282,7 +285,7 @@ void FileGenerator::Generate(io::Printer* printer) {
if (!MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
- if (HasDescriptorMethods(file_)) {
+ if (HasDescriptorMethods(file_, context_->EnforceLite())) {
EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
.Generate(printer);
} else {
@@ -294,7 +297,7 @@ void FileGenerator::Generate(io::Printer* printer) {
message_generators_[i]->GenerateInterface(printer);
message_generators_[i]->Generate(printer);
}
- if (HasGenericServices(file_)) {
+ if (HasGenericServices(file_, context_->EnforceLite())) {
for (int i = 0; i < file_->service_count(); i++) {
google::protobuf::scoped_ptr<ServiceGenerator> generator(
generator_factory_->NewServiceGenerator(file_->service(i)));
@@ -309,14 +312,18 @@ void FileGenerator::Generate(io::Printer* printer) {
extension_generators_[i]->Generate(printer);
}
- // Static variables.
+ // Static variables. We'd like them to be final if possible, but due to
+ // the JVM's 64k size limit on static blocks, we have to initialize some
+ // of them in methods; thus they cannot be final.
+ int static_block_bytecode_estimate = 0;
for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateStaticVariables(printer);
+ message_generators_[i]->GenerateStaticVariables(
+ printer, &static_block_bytecode_estimate);
}
printer->Print("\n");
- if (HasDescriptorMethods(file_)) {
+ if (HasDescriptorMethods(file_, context_->EnforceLite())) {
if (immutable_api_) {
GenerateDescriptorInitializationCodeForImmutable(printer);
} else {
@@ -358,9 +365,11 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
" getDescriptor() {\n"
" return descriptor;\n"
"}\n"
- "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+ "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n"
" descriptor;\n"
- "static {\n");
+ "static {\n",
+ // TODO(dweis): Mark this as final.
+ "final", "");
printer->Indent();
SharedCodeGenerator shared_code_generator(file_);
@@ -453,7 +462,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer*
" getDescriptor() {\n"
" return descriptor;\n"
"}\n"
- "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+ "private static final com.google.protobuf.Descriptors.FileDescriptor\n"
" descriptor;\n"
"static {\n");
printer->Indent();
@@ -549,7 +558,7 @@ void FileGenerator::GenerateSiblings(const string& package_dir,
vector<string>* file_list) {
if (MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
- if (HasDescriptorMethods(file_)) {
+ if (HasDescriptorMethods(file_, context_->EnforceLite())) {
EnumGenerator generator(file_->enum_type(i), immutable_api_,
context_.get());
GenerateSibling<EnumGenerator>(package_dir, java_package_,
@@ -582,7 +591,7 @@ void FileGenerator::GenerateSiblings(const string& package_dir,
message_generators_[i].get(),
&MessageGenerator::Generate);
}
- if (HasGenericServices(file_)) {
+ if (HasGenericServices(file_, context_->EnforceLite())) {
for (int i = 0; i < file_->service_count(); i++) {
google::protobuf::scoped_ptr<ServiceGenerator> generator(
generator_factory_->NewServiceGenerator(file_->service(i)));
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 080b3424..7dbeb94e 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -67,7 +67,8 @@ namespace java {
class FileGenerator {
public:
- FileGenerator(const FileDescriptor* file, bool immutable_api = true);
+ FileGenerator(const FileDescriptor* file, bool immutable_api = true,
+ bool enforce_lite = false);
~FileGenerator();
// Checks for problems that would otherwise lead to cryptic compile errors.
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index 6c6f7286..a46c7fc4 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -75,6 +75,7 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
bool generate_immutable_code = false;
bool generate_mutable_code = false;
bool generate_shared_code = false;
+ bool enforce_lite = false;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "output_list_file") {
output_list_file = options[i].second;
@@ -84,12 +85,21 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
generate_mutable_code = true;
} else if (options[i].first == "shared") {
generate_shared_code = true;
+ } else if (options[i].first == "lite") {
+ // When set, the protoc will generate the current files and all the
+ // transitive dependencies as lite runtime.
+ enforce_lite = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
+ if (enforce_lite && generate_mutable_code) {
+ *error = "lite runtime generator option cannot be used with mutable API.";
+ return false;
+ }
+
// By default we generate immutable code and shared code for immutable API.
if (!generate_immutable_code && !generate_mutable_code &&
!generate_shared_code) {
@@ -105,10 +115,12 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
vector<FileGenerator*> file_generators;
if (generate_immutable_code) {
- file_generators.push_back(new FileGenerator(file, /* immutable = */ true));
+ file_generators.push_back(
+ new FileGenerator(file, /* immutable = */ true, enforce_lite));
}
if (generate_mutable_code) {
- file_generators.push_back(new FileGenerator(file, /* mutable = */ false));
+ file_generators.push_back(
+ new FileGenerator(file, /* mutable = */ false, enforce_lite));
}
for (int i = 0; i < file_generators.size(); ++i) {
if (!file_generators[i]->Validate(error)) {
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
index 92ef851b..3218b410 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.cc
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -35,6 +35,7 @@
#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum_field.h>
#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_extension_lite.h>
#include <google/protobuf/compiler/java/java_field.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_message.h>
@@ -58,17 +59,20 @@ ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {}
MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
const Descriptor* descriptor) const {
- if (descriptor->file()->options().optimize_for() ==
- FileOptions::LITE_RUNTIME) {
- return new ImmutableMessageLiteGenerator(descriptor, context_);
- } else {
+ if (HasDescriptorMethods(descriptor, context_->EnforceLite())) {
return new ImmutableMessageGenerator(descriptor, context_);
+ } else {
+ return new ImmutableMessageLiteGenerator(descriptor, context_);
}
}
ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
const FieldDescriptor* descriptor) const {
- return new ImmutableExtensionGenerator(descriptor, context_);
+ if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) {
+ return new ImmutableExtensionGenerator(descriptor, context_);
+ } else {
+ return new ImmutableExtensionLiteGenerator(descriptor, context_);
+ }
}
ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator(
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 5392d6d7..c850423e 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -170,44 +170,41 @@ inline string ImmutableDefaultValue(const FieldDescriptor* field,
}
bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
-// Does this message class have generated parsing, serialization, and other
-// standard methods for which reflection-based fallback implementations exist?
-inline bool HasGeneratedMethods(const Descriptor* descriptor) {
- return descriptor->file()->options().optimize_for() !=
- FileOptions::CODE_SIZE;
-}
-
// Does this message have specialized equals() and hashCode() methods?
inline bool HasEqualsAndHashCode(const Descriptor* descriptor) {
return descriptor->file()->options().java_generate_equals_and_hash();
}
// Does this message class have descriptor and reflection methods?
-inline bool HasDescriptorMethods(const Descriptor* descriptor) {
- return descriptor->file()->options().optimize_for() !=
- FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const Descriptor* descriptor,
+ bool enforce_lite) {
+ return !enforce_lite &&
+ descriptor->file()->options().optimize_for() !=
+ FileOptions::LITE_RUNTIME;
}
-inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) {
- return descriptor->file()->options().optimize_for() !=
- FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const EnumDescriptor* descriptor,
+ bool enforce_lite) {
+ return !enforce_lite &&
+ descriptor->file()->options().optimize_for() !=
+ FileOptions::LITE_RUNTIME;
}
-inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
- return descriptor->options().optimize_for() !=
- FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const FileDescriptor* descriptor,
+ bool enforce_lite) {
+ return !enforce_lite &&
+ descriptor->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
// Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor *file) {
+inline bool HasGenericServices(const FileDescriptor *file, bool enforce_lite) {
return file->service_count() > 0 &&
- file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
+ HasDescriptorMethods(file, enforce_lite) &&
file->options().java_generic_services();
}
-inline bool IsLazy(const FieldDescriptor* descriptor) {
+inline bool IsLazy(const FieldDescriptor* descriptor, bool enforce_lite) {
// Currently, the proto-lite version suports lazy field.
// TODO(niwasaki): Support lazy fields also for other proto runtimes.
- if (descriptor->file()->options().optimize_for() !=
- FileOptions::LITE_RUNTIME) {
+ if (HasDescriptorMethods(descriptor->file(), enforce_lite)) {
return false;
}
return descriptor->options().lazy();
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
index 283ba1d3..a648f1c2 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -193,7 +193,7 @@ GenerateMergingCode(io::Printer* printer) const {
void ImmutableLazyMessageFieldLiteGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$name$_.setByteString(input.readBytes(), extensionRegistry);\n");
+ "$name$_.mergeFrom(input, extensionRegistry);\n");
printer->Print(variables_,
"$set_has_field_bit_message$;\n");
}
@@ -378,8 +378,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (!($has_oneof_case_message$)) {\n"
" $oneof_name$_ = new $lazy_type$();\n"
"}\n"
- "(($lazy_type$) $oneof_name$_).setByteString(\n"
- " input.readBytes(), extensionRegistry);\n"
+ "(($lazy_type$) $oneof_name$_).mergeFrom(input, extensionRegistry);\n"
"$set_oneof_case_message$;\n");
}
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 3e035c89..17c3646f 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -79,9 +79,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
const FieldGeneratorInfo* info,
- ClassNameResolver* name_resolver,
+ Context* context,
map<string, string>* variables) {
SetCommonFieldVariables(descriptor, info, variables);
+ ClassNameResolver* name_resolver = context->GetNameResolver();
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
@@ -123,8 +124,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+ (*variables)["on_changed"] = "onChanged();";
// For repeated fields, one bit is used for whether the array is immutable
// in the parsing constructor.
@@ -135,18 +135,12 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["default_entry"] = (*variables)["capitalized_name"] +
"DefaultEntryHolder.defaultEntry";
- if (HasDescriptorMethods(descriptor->file())) {
- (*variables)["lite"] = "";
- (*variables)["map_field_parameter"] = (*variables)["default_entry"];
- (*variables)["descriptor"] =
- name_resolver->GetImmutableClassName(descriptor->file()) +
- ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
- "_descriptor, ";
- } else {
- (*variables)["lite"] = "Lite";
- (*variables)["map_field_parameter"] = "";
- (*variables)["descriptor"] = "";
- }
+ (*variables)["lite"] = "";
+ (*variables)["map_field_parameter"] = (*variables)["default_entry"];
+ (*variables)["descriptor"] =
+ name_resolver->GetImmutableClassName(descriptor->file()) +
+ ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
+ "_descriptor, ";
}
} // namespace
@@ -159,7 +153,7 @@ ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
: descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
context->GetFieldGeneratorInfo(descriptor),
- name_resolver_, &variables_);
+ context, &variables_);
}
ImmutableMapFieldGenerator::
@@ -424,7 +418,7 @@ GenerateParsingCode(io::Printer* printer) const {
"$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
printer->Print(
variables_,
- "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
+ "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
" unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
"} else {\n"
" $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index d2039403..6bdebb0d 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -79,10 +79,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
const FieldGeneratorInfo* info,
- ClassNameResolver* name_resolver,
+ Context* context,
map<string, string>* variables) {
SetCommonFieldVariables(descriptor, info, variables);
+ ClassNameResolver* name_resolver = context->GetNameResolver();
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
const FieldDescriptor* key = KeyField(descriptor);
@@ -123,8 +124,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
(*variables)["default_entry"] = (*variables)["capitalized_name"] +
"DefaultEntryHolder.defaultEntry";
@@ -142,7 +141,7 @@ ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor,
: descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
context->GetFieldGeneratorInfo(descriptor),
- name_resolver_, &variables_);
+ context, &variables_);
}
ImmutableMapFieldLiteGenerator::
@@ -404,7 +403,7 @@ GenerateParsingCode(io::Printer* printer) const {
"$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
printer->Print(
variables_,
- "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
+ "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
" super.mergeLengthDelimitedField($number$, bytes);\n"
"} else {\n"
" $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 22a70c32..dfd8ad08 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -95,13 +95,15 @@ 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());
+ GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+ << "Generator factory error: A non-lite message generator is used to "
+ "generate lite messages.";
}
ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
-void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
+void ImmutableMessageGenerator::GenerateStaticVariables(
+ io::Printer* printer, int* bytecode_estimate) {
// Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
// used in the construction of descriptors, we have a tricky bootstrapping
// problem. To help control static initialization order, we make sure all
@@ -124,23 +126,29 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
} else {
vars["private"] = "private ";
}
+ if (*bytecode_estimate <= kMaxStaticSize) {
+ vars["final"] = "final ";
+ } else {
+ vars["final"] = "";
+ }
// The descriptor for this type.
printer->Print(vars,
// TODO(teboring): final needs to be added back. The way to fix it is to
// generate methods that can construct the types, and then still declare the
// types, and then init them in clinit with the new method calls.
- "$private$static com.google.protobuf.Descriptors.Descriptor\n"
+ "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n"
" internal_$identifier$_descriptor;\n");
+ *bytecode_estimate += 30;
// And the FieldAccessorTable.
- GenerateFieldAccessorTable(printer);
+ GenerateFieldAccessorTable(printer, bytecode_estimate);
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
- .GenerateStaticVariables(printer);
+ .GenerateStaticVariables(printer, bytecode_estimate);
}
}
@@ -183,7 +191,7 @@ int ImmutableMessageGenerator::GenerateStaticVariableInitializers(
}
void ImmutableMessageGenerator::
-GenerateFieldAccessorTable(io::Printer* printer) {
+GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate) {
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
@@ -193,10 +201,19 @@ GenerateFieldAccessorTable(io::Printer* printer) {
} else {
vars["private"] = "private ";
}
+ if (*bytecode_estimate <= kMaxStaticSize) {
+ vars["final"] = "final ";
+ } else {
+ vars["final"] = "";
+ }
printer->Print(vars,
- "$private$static\n"
+ "$private$static $final$\n"
" com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internal_$identifier$_fieldAccessorTable;\n");
+
+ // 6 bytes per field and oneof
+ *bytecode_estimate += 10 + 6 * descriptor_->field_count()
+ + 6 * descriptor_->oneof_decl_count();
}
int ImmutableMessageGenerator::
@@ -342,7 +359,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
printer->Print(
"}\n");
- if (HasGeneratedMethods(descriptor_)) {
+ if (context_->HasGeneratedMethods(descriptor_)) {
GenerateParsingConstructor(printer);
}
@@ -408,12 +425,20 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
"cap_oneof_name",
ToUpper(vars["oneof_name"]));
printer->Print(vars,
- "private int value = 0;\n"
+ "private final int value;\n"
"private $oneof_capitalized_name$Case(int value) {\n"
" this.value = value;\n"
"}\n");
printer->Print(vars,
+ "/**\n"
+ " * @deprecated Use {@link #forNumber(int)} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+ " return forNumber(value);\n"
+ "}\n"
+ "\n"
+ "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
" switch (value) {\n");
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -426,8 +451,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
}
printer->Print(
" case 0: return $cap_oneof_name$_NOT_SET;\n"
- " default: throw new java.lang.IllegalArgumentException(\n"
- " \"Value is undefined for this oneof enum.\");\n"
+ " default: return null;\n"
" }\n"
"}\n"
"public int getNumber() {\n"
@@ -440,7 +464,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
printer->Print(vars,
"public $oneof_capitalized_name$Case\n"
"get$oneof_capitalized_name$Case() {\n"
- " return $oneof_capitalized_name$Case.valueOf(\n"
+ " return $oneof_capitalized_name$Case.forNumber(\n"
" $oneof_name$Case_);\n"
"}\n"
"\n");
@@ -459,7 +483,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
printer->Print("\n");
}
- if (HasGeneratedMethods(descriptor_)) {
+ if (context_->HasGeneratedMethods(descriptor_)) {
GenerateIsInitialized(printer);
GenerateMessageSerializationMethods(printer);
}
@@ -664,34 +688,40 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
+ " return com.google.protobuf.GeneratedMessage\n"
+ " .parseWithIOException(PARSER, input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
+ " return com.google.protobuf.GeneratedMessage\n"
+ " .parseWithIOException(PARSER, input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input);"
+ " return com.google.protobuf.GeneratedMessage\n"
+ " .parseDelimitedWithIOException(PARSER, input);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input, extensionRegistry);"
+ " return com.google.protobuf.GeneratedMessage\n"
+ " .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
- " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
+ " return com.google.protobuf.GeneratedMessage\n"
+ " .parseWithIOException(PARSER, input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
+ " return com.google.protobuf.GeneratedMessage\n"
+ " .parseWithIOException(PARSER, input, extensionRegistry);\n"
"}\n"
"\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -1049,22 +1079,52 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
+ // hashCode non-oneofs.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
- bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
- if (check_has_bits) {
+ if (field->containing_oneof() == NULL) {
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
+ printer->Print(
+ "if (has$name$()) {\n",
+ "name", info->capitalized_name);
+ printer->Indent();
+ }
+ field_generators_.get(field).GenerateHashCode(printer);
+ if (check_has_bits) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ }
+
+ // hashCode oneofs.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "switch ($oneof_name$Case_) {\n",
+ "oneof_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
printer->Print(
- "if (has$name$()) {\n",
- "name", info->capitalized_name);
+ "case $field_number$:\n",
+ "field_number",
+ SimpleItoa(field->number()));
printer->Indent();
- }
- field_generators_.get(field).GenerateHashCode(printer);
- if (check_has_bits) {
+ field_generators_.get(field).GenerateHashCode(printer);
+ printer->Print("break;\n");
printer->Outdent();
- printer->Print("}\n");
}
+ printer->Print(
+ "case 0:\n"
+ "default:\n");
+ printer->Outdent();
+ printer->Print("}\n");
}
+
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"hash = hashFields(hash, getExtensionFields());\n");
@@ -1105,7 +1165,8 @@ GenerateParsingConstructor(io::Printer* printer) {
printer->Print(
"private $classname$(\n"
" com.google.protobuf.CodedInputStream input,\n"
- " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n",
"classname", descriptor_->name());
printer->Indent();
@@ -1215,10 +1276,10 @@ GenerateParsingConstructor(io::Printer* printer) {
printer->Outdent();
printer->Print(
"} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
- " throw new RuntimeException(e.setUnfinishedMessage(this));\n"
+ " throw e.setUnfinishedMessage(this);\n"
"} catch (java.io.IOException e) {\n"
- " throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n"
- " .setUnfinishedMessage(this));\n"
+ " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e).setUnfinishedMessage(this);\n"
"} finally {\n");
printer->Indent();
@@ -1260,20 +1321,9 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n",
"classname", descriptor_->name());
- if (HasGeneratedMethods(descriptor_)) {
- // The parsing constructor throws an InvalidProtocolBufferException via a
- // RuntimeException to aid in method pruning. We unwrap it here.
+ if (context_->HasGeneratedMethods(descriptor_)) {
printer->Print(
- " try {\n"
- " return new $classname$(input, extensionRegistry);\n"
- " } catch (RuntimeException e) {\n"
- " if (e.getCause() instanceof\n"
- " com.google.protobuf.InvalidProtocolBufferException) {\n"
- " throw (com.google.protobuf.InvalidProtocolBufferException)\n"
- " e.getCause();\n"
- " }\n"
- " throw e;\n"
- " }\n",
+ " return new $classname$(input, extensionRegistry);\n",
"classname", descriptor_->name());
} else {
// When parsing constructor isn't generated, use builder to parse
@@ -1328,14 +1378,39 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) {
void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
printer->Print(
"private static String getTypeUrl(\n"
+ " java.lang.String typeUrlPrefix,\n"
" com.google.protobuf.Descriptors.Descriptor descriptor) {\n"
- " return \"type.googleapis.com/\" + descriptor.getFullName();\n"
+ " return typeUrlPrefix.endsWith(\"/\")\n"
+ " ? typeUrlPrefix + descriptor.getFullName()\n"
+ " : typeUrlPrefix + \"/\" + descriptor.getFullName();\n"
+ "}\n"
+ "\n"
+ "private static String getTypeNameFromTypeUrl(\n"
+ " java.lang.String typeUrl) {\n"
+ " int pos = typeUrl.lastIndexOf('/');\n"
+ " return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n"
"}\n"
"\n"
"public static <T extends com.google.protobuf.Message> Any pack(\n"
" T message) {\n"
" return Any.newBuilder()\n"
- " .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n"
+ " .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n"
+ " message.getDescriptorForType()))\n"
+ " .setValue(message.toByteString())\n"
+ " .build();\n"
+ "}\n"
+ "\n"
+ "/**\n"
+ " * Packs a message uisng the given type URL prefix. The type URL will\n"
+ " * be constructed by concatenating the message type's full name to the\n"
+ " * prefix with an optional \"/\" separator if the prefix doesn't end\n"
+ " * with \"/\" already.\n"
+ " */\n"
+ "public static <T extends com.google.protobuf.Message> Any pack(\n"
+ " T message, java.lang.String typeUrlPrefix) {\n"
+ " return Any.newBuilder()\n"
+ " .setTypeUrl(getTypeUrl(typeUrlPrefix,\n"
+ " message.getDescriptorForType()))\n"
" .setValue(message.toByteString())\n"
" .build();\n"
"}\n"
@@ -1344,8 +1419,8 @@ void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
" java.lang.Class<T> clazz) {\n"
" T defaultInstance =\n"
" com.google.protobuf.Internal.getDefaultInstance(clazz);\n"
- " return getTypeUrl().equals(\n"
- " getTypeUrl(defaultInstance.getDescriptorForType()));\n"
+ " return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n"
+ " defaultInstance.getDescriptorForType().getFullName());\n"
"}\n"
"\n"
"private volatile com.google.protobuf.Message cachedUnpackValue;\n"
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index be5bfb07..e9fc57c2 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -56,6 +56,8 @@ namespace protobuf {
namespace compiler {
namespace java {
+static const int kMaxStaticSize = 1 << 15; // aka 32k
+
class MessageGenerator {
public:
explicit MessageGenerator(const Descriptor* descriptor);
@@ -64,7 +66,8 @@ class MessageGenerator {
// All static variables have to be declared at the top-level of the file
// so that we can control initialization order, which is important for
// DescriptorProto bootstrapping to work.
- virtual void GenerateStaticVariables(io::Printer* printer) = 0;
+ virtual void GenerateStaticVariables(
+ io::Printer* printer, int* bytecode_estimate) = 0;
// Output code which initializes the static variables generated by
// GenerateStaticVariables(). Returns an estimate of bytecode size.
@@ -96,14 +99,15 @@ class ImmutableMessageGenerator : public MessageGenerator {
virtual void Generate(io::Printer* printer);
virtual void GenerateInterface(io::Printer* printer);
virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
- virtual void GenerateStaticVariables(io::Printer* printer);
+ virtual void GenerateStaticVariables(
+ io::Printer* printer, int* bytecode_estimate);
// Returns an estimate of the number of bytes the printed code will compile to
virtual int GenerateStaticVariableInitializers(io::Printer* printer);
private:
- void GenerateFieldAccessorTable(io::Printer* printer);
+ void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate);
// Returns an estimate of the number of bytes the printed code will compile to
int GenerateFieldAccessorTableInitializer(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index 5d535034..b3e9e986 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -81,8 +81,9 @@ MessageBuilderGenerator::MessageBuilderGenerator(
: descriptor_(descriptor), context_(context),
name_resolver_(context->GetNameResolver()),
field_generators_(descriptor, context_) {
- GOOGLE_CHECK_NE(
- FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+ GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+ << "Generator factory error: A non-lite message generator is used to "
+ "generate lite messages.";
}
MessageBuilderGenerator::~MessageBuilderGenerator() {}
@@ -113,7 +114,7 @@ Generate(io::Printer* printer) {
GenerateDescriptorMethods(printer);
GenerateCommonBuilderMethods(printer);
- if (HasGeneratedMethods(descriptor_)) {
+ if (context_->HasGeneratedMethods(descriptor_)) {
GenerateIsInitialized(printer);
GenerateBuilderParsingMethods(printer);
}
@@ -134,7 +135,7 @@ Generate(io::Printer* printer) {
printer->Print(vars,
"public $oneof_capitalized_name$Case\n"
" get$oneof_capitalized_name$Case() {\n"
- " return $oneof_capitalized_name$Case.valueOf(\n"
+ " return $oneof_capitalized_name$Case.forNumber(\n"
" $oneof_name$Case_);\n"
"}\n"
"\n"
@@ -439,7 +440,7 @@ GenerateCommonBuilderMethods(io::Printer* printer) {
// -----------------------------------------------------------------
- if (HasGeneratedMethods(descriptor_)) {
+ if (context_->HasGeneratedMethods(descriptor_)) {
printer->Print(
"public Builder mergeFrom(com.google.protobuf.Message other) {\n"
" if (other instanceof $classname$) {\n"
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
index 8719d00d..dd429dc9 100644
--- a/src/google/protobuf/compiler/java/java_message_builder_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -81,8 +81,9 @@ MessageBuilderLiteGenerator::MessageBuilderLiteGenerator(
: descriptor_(descriptor), context_(context),
name_resolver_(context->GetNameResolver()),
field_generators_(descriptor, context_) {
- GOOGLE_CHECK_EQ(
- FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+ GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+ << "Generator factory error: A lite message generator is used to "
+ "generate non-lite messages.";
}
MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {}
@@ -148,20 +149,6 @@ Generate(io::Printer* printer) {
.GenerateBuilderMembers(printer);
}
- if (!PreserveUnknownFields(descriptor_)) {
- printer->Print(
- "public final Builder setUnknownFields(\n"
- " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
- " return this;\n"
- "}\n"
- "\n"
- "public final Builder mergeUnknownFields(\n"
- " final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
- " return this;\n"
- "}\n"
- "\n");
- }
-
printer->Print(
"\n"
"// @@protoc_insertion_point(builder_scope:$full_name$)\n",
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index b5f8e626..455516f6 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -70,8 +70,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+ (*variables)["on_changed"] = "onChanged();";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
index 356520ec..049679df 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -70,8 +70,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -867,7 +865,6 @@ GenerateMergingCode(io::Printer* printer) const {
" ensure$capitalized_name$IsMutable();\n"
" $name$_.addAll(other.$name$_);\n"
" }\n"
- " $on_changed$\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 94ed2c39..14cc908b 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -46,7 +46,7 @@
#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_enum_lite.h>
-#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_extension_lite.h>
#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_message_builder.h>
@@ -87,19 +87,20 @@ ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator(
: MessageGenerator(descriptor), context_(context),
name_resolver_(context->GetNameResolver()),
field_generators_(descriptor, context_) {
- GOOGLE_CHECK_EQ(
- FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+ GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+ << "Generator factory error: A lite message generator is used to "
+ "generate non-lite messages.";
}
ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
void ImmutableMessageLiteGenerator::GenerateStaticVariables(
- io::Printer* printer) {
+ io::Printer* printer, int* bytecode_estimate) {
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
- .GenerateStaticVariables(printer);
+ .GenerateStaticVariables(printer, bytecode_estimate);
}
}
@@ -197,6 +198,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
}
printer->Indent();
+
GenerateParsingConstructor(printer);
// Nested types
@@ -259,12 +261,20 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
"cap_oneof_name",
ToUpper(vars["oneof_name"]));
printer->Print(vars,
- "private int value = 0;\n"
+ "private final int value;\n"
"private $oneof_capitalized_name$Case(int value) {\n"
" this.value = value;\n"
"}\n");
printer->Print(vars,
+ "/**\n"
+ " * @deprecated Use {@link #forNumber(int)} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+ " return forNumber(value);\n"
+ "}\n"
+ "\n"
+ "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
" switch (value) {\n");
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -277,8 +287,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
}
printer->Print(
" case 0: return $cap_oneof_name$_NOT_SET;\n"
- " default: throw new java.lang.IllegalArgumentException(\n"
- " \"Value is undefined for this oneof enum.\");\n"
+ " default: return null;\n"
" }\n"
"}\n"
"public int getNumber() {\n"
@@ -291,7 +300,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
printer->Print(vars,
"public $oneof_capitalized_name$Case\n"
"get$oneof_capitalized_name$Case() {\n"
- " return $oneof_capitalized_name$Case.valueOf(\n"
+ " return $oneof_capitalized_name$Case.forNumber(\n"
" $oneof_name$Case_);\n"
"}\n"
"\n"
@@ -317,7 +326,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
GenerateEqualsAndHashCode(printer);
}
-
GenerateParseFromMethods(printer);
GenerateBuilder(printer);
@@ -446,7 +454,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
// because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
// the outer class's FileDescriptor.
for (int i = 0; i < descriptor_->extension_count(); i++) {
- ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+ ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
.Generate(printer);
}
@@ -557,9 +565,6 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
" return size;\n"
"}\n"
"\n");
-
- printer->Print(
- "private static final long serialVersionUID = 0L;\n");
}
void ImmutableMessageLiteGenerator::
@@ -571,54 +576,62 @@ GenerateParseFromMethods(io::Printer* printer) {
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return parser().parseFrom(data);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, data);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return parser().parseFrom(data, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, data, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(byte[] data)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return parser().parseFrom(data);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, data);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" byte[] data,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return parser().parseFrom(data, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, data, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return parser().parseFrom(input);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return parser().parseFrom(input, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return parser().parseDelimitedFrom(input);\n"
+ " return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return parser().parseDelimitedFrom(input, extensionRegistry);\n"
+ " return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
- " return parser().parseFrom(input);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return parser().parseFrom(input, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+ " DEFAULT_INSTANCE, input, extensionRegistry);\n"
"}\n"
"\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -906,24 +919,61 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
"classname", name_resolver_->GetImmutableClassName(descriptor_));
printer->Print("boolean result = true;\n");
+ // Compare non-oneofs.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
- bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
- if (check_has_bits) {
+ if (field->containing_oneof() == NULL) {
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
+ printer->Print(
+ "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");
+ }
+ }
+ }
+
+ // Compare oneofs.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "result = result && get$oneof_capitalized_name$Case().equals(\n"
+ " other.get$oneof_capitalized_name$Case());\n",
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name);
+ printer->Print(
+ "if (!result) return false;\n"
+ "switch ($oneof_name$Case_) {\n",
+ "oneof_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
printer->Print(
- "result = result && (has$name$() == other.has$name$());\n"
- "if (has$name$()) {\n",
- "name", info->capitalized_name);
+ "case $field_number$:\n",
+ "field_number",
+ SimpleItoa(field->number()));
printer->Indent();
- }
- field_generators_.get(field).GenerateEqualsCode(printer);
- if (check_has_bits) {
+ field_generators_.get(field).GenerateEqualsCode(printer);
+ printer->Print("break;\n");
printer->Outdent();
- printer->Print(
- "}\n");
}
+ printer->Print(
+ "case 0:\n"
+ "default:\n");
+ 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
@@ -957,21 +1007,50 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
+ // hashCode non-oneofs.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
- bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
- if (check_has_bits) {
+ if (field->containing_oneof() == NULL) {
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
+ printer->Print(
+ "if (has$name$()) {\n",
+ "name", info->capitalized_name);
+ printer->Indent();
+ }
+ field_generators_.get(field).GenerateHashCode(printer);
+ if (check_has_bits) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ }
+
+ // hashCode oneofs.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "switch ($oneof_name$Case_) {\n",
+ "oneof_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
printer->Print(
- "if (has$name$()) {\n",
- "name", info->capitalized_name);
+ "case $field_number$:\n",
+ "field_number",
+ SimpleItoa(field->number()));
printer->Indent();
- }
- field_generators_.get(field).GenerateHashCode(printer);
- if (check_has_bits) {
+ field_generators_.get(field).GenerateHashCode(printer);
+ printer->Print("break;\n");
printer->Outdent();
- printer->Print("}\n");
}
+ printer->Print(
+ "case 0:\n"
+ "default:\n");
+ printer->Outdent();
+ printer->Print("}\n");
}
printer->Print(
@@ -990,7 +1069,7 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
void ImmutableMessageLiteGenerator::
GenerateExtensionRegistrationCode(io::Printer* printer) {
for (int i = 0; i < descriptor_->extension_count(); i++) {
- ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+ ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
.GenerateRegistrationCode(printer);
}
@@ -1167,7 +1246,6 @@ void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) {
}
}
-
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index 2bd3cdd4..c8ee99bd 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -54,7 +54,8 @@ class ImmutableMessageLiteGenerator : public MessageGenerator {
virtual void Generate(io::Printer* printer);
virtual void GenerateInterface(io::Printer* printer);
virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
- virtual void GenerateStaticVariables(io::Printer* printer);
+ virtual void GenerateStaticVariables(
+ io::Printer* printer, int* bytecode_estimate);
virtual int GenerateStaticVariableInitializers(io::Printer* printer);
private:
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
index 0c363f9f..bffe4f16 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.cc
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -259,6 +259,13 @@ string ClassNameResolver::GetJavaImmutableClassName(
descriptor->file(), true);
}
+string ClassNameResolver::GetJavaImmutableClassName(
+ const EnumDescriptor* descriptor) {
+ return GetJavaClassFullName(
+ ClassNameWithoutPackage(descriptor, true),
+ descriptor->file(), true);
+}
+
} // namespace java
} // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
index ab60b0a0..570d8d8f 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.h
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -98,6 +98,7 @@ class ClassNameResolver {
// For example:
// com.package.OuterClass$OuterMessage$InnerMessage
string GetJavaImmutableClassName(const Descriptor* descriptor);
+ string GetJavaImmutableClassName(const EnumDescriptor* descriptor);
private:
// Get the full name of a Java class by prepending the Java package name
// or outer class name.
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 178bbe19..e42ec280 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -75,12 +75,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
"" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
(*variables)["capitalized_type"] =
GetCapitalizedType(descriptor, /* immutable = */ true);
- if (descriptor->is_packed()) {
- (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag(
- descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
- } else {
- (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
- }
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
if (IsReferenceType(GetJavaType(descriptor))) {
@@ -99,8 +94,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
if (fixed_size != -1) {
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
}
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+ (*variables)["on_changed"] = "onChanged();";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -606,7 +600,7 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
if (descriptor_->is_packed() &&
- HasGeneratedMethods(descriptor_->containing_type())) {
+ context_->HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize = -1;\n");
}
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 5a7bf82d..d277e4f3 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -129,8 +129,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
if (fixed_size != -1) {
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
}
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -635,7 +633,7 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
if (descriptor_->options().packed() &&
- HasGeneratedMethods(descriptor_->containing_type())) {
+ context_->HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize = -1;\n");
}
@@ -758,7 +756,6 @@ GenerateMergingCode(io::Printer* printer) const {
" ensure$capitalized_name$IsMutable();\n"
" $name$_.addAll(other.$name$_);\n"
" }\n"
- " $on_changed$\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index 70177367..74253c3f 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -52,8 +52,9 @@ namespace compiler {
namespace java {
SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file)
- : name_resolver_(new ClassNameResolver), file_(file) {
-}
+ : name_resolver_(new ClassNameResolver),
+ enforce_lite_(false),
+ file_(file) {}
SharedCodeGenerator::~SharedCodeGenerator() {
}
@@ -63,7 +64,7 @@ void SharedCodeGenerator::Generate(GeneratorContext* context,
string java_package = FileJavaPackage(file_);
string package_dir = JavaPackageToDir(java_package);
- if (HasDescriptorMethods(file_)) {
+ if (HasDescriptorMethods(file_, enforce_lite_)) {
// Generate descriptors.
string classname = name_resolver_->GetDescriptorClassName(file_);
string filename = package_dir + classname + ".java";
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h
index 38a32fc2..3b573c07 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.h
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h
@@ -72,6 +72,10 @@ class SharedCodeGenerator {
void Generate(GeneratorContext* generator_context,
vector<string>* file_list);
+ void SetEnforceLite(bool value) {
+ enforce_lite_ = value;
+ }
+
void GenerateDescriptors(io::Printer* printer);
private:
@@ -81,6 +85,7 @@ class SharedCodeGenerator {
bool ShouldIncludeDependency(const FileDescriptor* descriptor);
google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
+ bool enforce_lite_;
const FileDescriptor* file_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
};
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 7f757e47..b67eeb53 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -87,8 +87,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+ (*variables)["on_changed"] = "onChanged();";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -408,15 +407,6 @@ GenerateParsingCode(io::Printer* printer) const {
"java.lang.String s = input.readStringRequireUtf8();\n"
"$set_has_field_bit_message$\n"
"$name$_ = s;\n");
- } else if (!HasDescriptorMethods(descriptor_->file())) {
- // Lite runtime should attempt to reduce allocations by attempting to
- // construct the string directly from the input stream buffer. This avoids
- // spurious intermediary ByteString allocations, cutting overall allocations
- // in half.
- printer->Print(variables_,
- "java.lang.String s = input.readString();\n"
- "$set_has_field_bit_message$\n"
- "$name$_ = s;\n");
} else {
printer->Print(variables_,
"com.google.protobuf.ByteString bs = input.readBytes();\n"
@@ -668,15 +658,6 @@ GenerateParsingCode(io::Printer* printer) const {
"java.lang.String s = input.readStringRequireUtf8();\n"
"$set_oneof_case_message$;\n"
"$oneof_name$_ = s;\n");
- } else if (!HasDescriptorMethods(descriptor_->file())) {
- // Lite runtime should attempt to reduce allocations by attempting to
- // construct the string directly from the input stream buffer. This avoids
- // spurious intermediary ByteString allocations, cutting overall allocations
- // in half.
- printer->Print(variables_,
- "java.lang.String s = input.readString();\n"
- "$set_oneof_case_message$;\n"
- "$oneof_name$_ = s;\n");
} else {
printer->Print(variables_,
"com.google.protobuf.ByteString bs = input.readBytes();\n"
@@ -934,13 +915,6 @@ GenerateParsingCode(io::Printer* printer) const {
if (CheckUtf8(descriptor_)) {
printer->Print(variables_,
"java.lang.String s = input.readStringRequireUtf8();\n");
- } else if (!HasDescriptorMethods(descriptor_->file())) {
- // Lite runtime should attempt to reduce allocations by attempting to
- // construct the string directly from the input stream buffer. This avoids
- // spurious intermediary ByteString allocations, cutting overall allocations
- // in half.
- printer->Print(variables_,
- "java.lang.String s = input.readString();\n");
} else {
printer->Print(variables_,
"com.google.protobuf.ByteString bs = input.readBytes();\n");
@@ -950,7 +924,7 @@ GenerateParsingCode(io::Printer* printer) const {
" $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
" $set_mutable_bit_parser$;\n"
"}\n");
- if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
+ if (CheckUtf8(descriptor_)) {
printer->Print(variables_,
"$name$_.add(s);\n");
} else {
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
index eb5964bd..9012ab5e 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -84,8 +84,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
- (*variables)["on_changed"] =
- HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -103,7 +101,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["clear_has_field_bit_message"] = "";
(*variables)["is_field_present_message"] =
- "!get" + (*variables)["capitalized_name"] + ".isEmpty()";
+ "!" + (*variables)["name"] + "_.isEmpty()";
}
// For repeated builders, the underlying list tracks mutability state.
@@ -309,13 +307,11 @@ GenerateMergingCode(io::Printer* printer) const {
"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");
}
}
@@ -528,8 +524,7 @@ GenerateMergingCode(io::Printer* printer) const {
// 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");
+ "$oneof_name$_ = other.$oneof_name$_;\n");
}
void ImmutableStringOneofFieldLiteGenerator::
@@ -792,7 +787,6 @@ GenerateMergingCode(io::Printer* printer) const {
" ensure$capitalized_name$IsMutable();\n"
" $name$_.addAll(other.$name$_);\n"
" }\n"
- " $on_changed$\n"
"}\n");
}
@@ -819,13 +813,8 @@ GenerateParsingCode(io::Printer* printer) const {
"if (!$is_mutable$) {\n"
" $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n"
"}\n");
- if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
- printer->Print(variables_,
- "$name$_.add(s);\n");
- } else {
- printer->Print(variables_,
- "$name$_.add(bs);\n");
- }
+ printer->Print(variables_,
+ "$name$_.add(s);\n");
}
void RepeatedImmutableStringFieldLiteGenerator::
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index a33eba1b..a342e6bb 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -68,12 +68,7 @@ void UpdateParamsRecursively(Params& params,
}
if (file->options().has_java_package()) {
string result = file->options().java_package();
- if (!file->options().javanano_use_deprecated_package()) {
- if (!result.empty()) {
- result += ".";
- }
- result += "nano";
- }
+ result += "nano";
params.set_java_package(
file->name(), result);
}
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index 5465655f..02811a24 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -201,12 +201,10 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) {
result += file->package();
}
- if (!file->options().javanano_use_deprecated_package()) {
- if (!result.empty()) {
- result += ".";
- }
- result += "nano";
+ if (!result.empty()) {
+ result += ".";
}
+ result += "nano";
return result;
}
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 0de7e2c6..534a5b5b 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -28,7 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <google/protobuf/compiler/js/js_generator.h>
+#include "google/protobuf/compiler/js/js_generator.h"
#include <assert.h>
#include <algorithm>
@@ -123,6 +123,16 @@ static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
namespace {
+// The mode of operation for bytes fields. Historically JSPB always carried
+// bytes as JS {string}, containing base64 content by convention. With binary
+// and proto3 serialization the new convention is to represent it as binary
+// data in Uint8Array. See b/26173701 for background on the migration.
+enum BytesMode {
+ BYTES_DEFAULT, // Default type for getBytesField to return.
+ BYTES_B64, // Explicitly coerce to base64 string where needed.
+ BYTES_U8, // Explicitly coerce to Uint8Array where needed.
+};
+
bool IsReserved(const string& ident) {
for (int i = 0; i < kNumKeyword; i++) {
if (ident == kKeyword[i]) {
@@ -134,7 +144,7 @@ bool IsReserved(const string& ident) {
// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
// suffix stripped.
-// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc.
+// TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc.
string StripProto(const string& filename) {
const char* suffix = HasSuffixString(filename, ".protodevel")
? ".protodevel" : ".proto";
@@ -144,9 +154,7 @@ string StripProto(const string& filename) {
// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
// file foo/bar/baz.js.
string GetJSFilename(const string& filename) {
- const char* suffix = HasSuffixString(filename, ".protodevel")
- ? ".protodevel" : ".proto";
- return StripSuffixString(filename, suffix) + "_pb.js";
+ return StripProto(filename) + "_pb.js";
}
// Given a filename like foo/bar/baz.proto, returns the root directory
@@ -385,15 +393,47 @@ string ToFileName(const string& input) {
return result;
}
+// When we're generating one output file per type name, this is the filename
+// that top-level extensions should go in.
+string GetExtensionFileName(const GeneratorOptions& options,
+ const FileDescriptor* file) {
+ return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js";
+}
+
+// When we're generating one output file per type name, this is the filename
+// that a top-level message should go in.
+string GetMessageFileName(const GeneratorOptions& options,
+ const Descriptor* desc) {
+ return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+}
+
+// When we're generating one output file per type name, this is the filename
+// that a top-level message should go in.
+string GetEnumFileName(const GeneratorOptions& options,
+ const EnumDescriptor* desc) {
+ return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+}
+
// Returns the message/response ID, if set.
string GetMessageId(const Descriptor* desc) {
return string();
}
+bool IgnoreExtensionField(const FieldDescriptor* field) {
+ // Exclude descriptor extensions from output "to avoid clutter" (from original
+ // codegen).
+ return field->is_extension() &&
+ field->containing_type()->file()->name() ==
+ "google/protobuf/descriptor.proto";
+}
+
// Used inside Google only -- do not remove.
bool IsResponse(const Descriptor* desc) { return false; }
-bool IgnoreField(const FieldDescriptor* field) { return false; }
+
+bool IgnoreField(const FieldDescriptor* field) {
+ return IgnoreExtensionField(field);
+}
// Does JSPB ignore this entire oneof? True only if all fields are ignored.
@@ -438,12 +478,32 @@ string JSObjectFieldName(const FieldDescriptor* field) {
return name;
}
+string JSByteGetterSuffix(BytesMode bytes_mode) {
+ switch (bytes_mode) {
+ case BYTES_DEFAULT:
+ return "";
+ case BYTES_B64:
+ return "B64";
+ case BYTES_U8:
+ return "U8";
+ default:
+ assert(false);
+ }
+}
+
// Returns the field name as a capitalized portion of a getter/setter method
// name, e.g. MyField for .getMyField().
-string JSGetterName(const FieldDescriptor* field) {
+string JSGetterName(const FieldDescriptor* field,
+ BytesMode bytes_mode = BYTES_DEFAULT) {
string name = JSIdent(field,
/* is_upper_camel = */ true,
/* is_map = */ false);
+ if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ string suffix = JSByteGetterSuffix(bytes_mode);
+ if (!suffix.empty()) {
+ name += "_as" + suffix;
+ }
+ }
if (name == "Extension" || name == "JsPbMessageId") {
// Avoid conflicts with base-class names.
name += "$";
@@ -504,8 +564,7 @@ string JSOneofIndex(const OneofDescriptor* oneof) {
return SimpleItoa(index);
}
-// Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only
-// need to handle the BMP (16-bit range) here.
+// Decodes a codepoint in \x0000 -- \xFFFF.
uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
if (*length == 0) {
return 0;
@@ -542,80 +601,56 @@ uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
}
// Escapes the contents of a string to be included within double-quotes ("") in
-// JavaScript. |is_utf8| determines whether the input data (in a C++ string of
-// chars) is UTF-8 encoded (in which case codepoints become JavaScript string
-// characters, escaped with 16-bit hex escapes where necessary) or raw binary
-// (in which case bytes become JavaScript string characters 0 -- 255).
-string EscapeJSString(const string& in, bool is_utf8) {
- string result;
+// JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
+// Returns false if |out| was truncated because |in| contained invalid UTF-8 or
+// codepoints outside the BMP.
+// TODO(lukestebbing): Support codepoints outside the BMP.
+bool EscapeJSString(const string& in, string* out) {
size_t decoded = 0;
for (size_t i = 0; i < in.size(); i += decoded) {
uint16 codepoint = 0;
- if (is_utf8) {
- // Decode the next UTF-8 codepoint.
- size_t have_bytes = in.size() - i;
- uint8 bytes[3] = {
+ // Decode the next UTF-8 codepoint.
+ size_t have_bytes = in.size() - i;
+ uint8 bytes[3] = {
static_cast<uint8>(in[i]),
static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
- };
- codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
- if (have_bytes == 0) {
- break;
- }
- decoded = have_bytes;
- } else {
- codepoint = static_cast<uint16>(static_cast<uint8>(in[i]));
- decoded = 1;
+ };
+ codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
+ if (have_bytes == 0) {
+ return false;
}
-
- // Next byte -- used for minimal octal escapes below.
- char next_byte = (i + decoded) < in.size() ?
- in[i + decoded] : 0;
- bool pad_octal = (next_byte >= '0' && next_byte <= '7');
+ decoded = have_bytes;
switch (codepoint) {
- case '\0': result += pad_octal ? "\\000" : "\\0"; break;
- case '\b': result += "\\\b"; break;
- case '\t': result += "\\\t"; break;
- case '\n': result += "\\\n"; break;
- case '\r': result += "\\\r"; break;
- case '\f': result += "\\\f"; break;
- case '\\': result += "\\\\"; break;
- case '"': result += pad_octal ? "\\042" : "\\42"; break;
- case '&': result += pad_octal ? "\\046" : "\\46"; break;
- case '\'': result += pad_octal ? "\\047" : "\\47"; break;
- case '<': result += pad_octal ? "\\074" : "\\74"; break;
- case '=': result += pad_octal ? "\\075" : "\\75"; break;
- case '>': result += pad_octal ? "\\076" : "\\76"; break;
+ case '\'': *out += "\\x27"; break;
+ case '"': *out += "\\x22"; break;
+ case '<': *out += "\\x3c"; break;
+ case '=': *out += "\\x3d"; break;
+ case '>': *out += "\\x3e"; break;
+ case '&': *out += "\\x26"; break;
+ case '\b': *out += "\\b"; break;
+ case '\t': *out += "\\t"; break;
+ case '\n': *out += "\\n"; break;
+ case '\f': *out += "\\f"; break;
+ case '\r': *out += "\\r"; break;
+ case '\\': *out += "\\\\"; break;
default:
- // All other non-ASCII codepoints are escaped.
- // Original codegen uses hex for >= 0x100 and octal for others.
+ // TODO(lukestebbing): Once we're supporting codepoints outside the BMP,
+ // use a single Unicode codepoint escape if the output language is
+ // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
if (codepoint >= 0x20 && codepoint <= 0x7e) {
- result += static_cast<char>(codepoint);
+ *out += static_cast<char>(codepoint);
+ } else if (codepoint >= 0x100) {
+ *out += StringPrintf("\\u%04x", codepoint);
} else {
- if (codepoint >= 0x100) {
- result += StringPrintf("\\u%04x", codepoint);
- } else {
- if (pad_octal || codepoint >= 0100) {
- result += "\\";
- result += ('0' + ((codepoint >> 6) & 07));
- result += ('0' + ((codepoint >> 3) & 07));
- result += ('0' + ((codepoint >> 0) & 07));
- } else if (codepoint >= 010) {
- result += "\\";
- result += ('0' + ((codepoint >> 3) & 07));
- result += ('0' + ((codepoint >> 0) & 07));
- } else {
- result += "\\";
- result += ('0' + ((codepoint >> 0) & 07));
- }
- }
+ *out += StringPrintf("\\x%02x", codepoint);
}
break;
}
}
- return result;
+ return true;
}
string EscapeBase64(const string& in) {
@@ -740,11 +775,17 @@ string JSFieldDefault(const FieldDescriptor* field) {
return DoubleToString(field->default_value_double());
case FieldDescriptor::CPPTYPE_STRING:
if (field->type() == FieldDescriptor::TYPE_STRING) {
- return "\"" + EscapeJSString(field->default_value_string(), true) +
- "\"";
- } else {
- return "\"" + EscapeBase64(field->default_value_string()) +
- "\"";
+ string out;
+ bool is_valid = EscapeJSString(field->default_value_string(), &out);
+ if (!is_valid) {
+ // TODO(lukestebbing): Decide whether this should be a hard error.
+ GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name()
+ << " was truncated since it contained invalid UTF-8 or"
+ " codepoints outside the basic multilingual plane.";
+ }
+ return "\"" + out + "\"";
+ } else { // Bytes
+ return "\"" + EscapeBase64(field->default_value_string()) + "\"";
}
case FieldDescriptor::CPPTYPE_MESSAGE:
return "null";
@@ -801,8 +842,27 @@ string JSIntegerTypeName(const FieldDescriptor* field) {
return "number";
}
+string JSStringTypeName(const GeneratorOptions& options,
+ const FieldDescriptor* field,
+ BytesMode bytes_mode) {
+ if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ switch (bytes_mode) {
+ case BYTES_DEFAULT:
+ return "(string|Uint8Array)";
+ case BYTES_B64:
+ return "string";
+ case BYTES_U8:
+ return "Uint8Array";
+ default:
+ assert(false);
+ }
+ }
+ return "string";
+}
+
string JSTypeName(const GeneratorOptions& options,
- const FieldDescriptor* field) {
+ const FieldDescriptor* field,
+ BytesMode bytes_mode) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_BOOL:
return "boolean";
@@ -819,7 +879,7 @@ string JSTypeName(const GeneratorOptions& options,
case FieldDescriptor::CPPTYPE_DOUBLE:
return "number";
case FieldDescriptor::CPPTYPE_STRING:
- return "string";
+ return JSStringTypeName(options, field, bytes_mode);
case FieldDescriptor::CPPTYPE_ENUM:
return GetPath(options, field->enum_type());
case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -836,20 +896,26 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options,
bool force_optional,
bool force_present,
bool singular_if_not_packed,
- bool always_singular) {
+ BytesMode bytes_mode = BYTES_DEFAULT) {
bool is_primitive =
(field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
- field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE);
+ field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
+ (field->type() != FieldDescriptor::TYPE_BYTES ||
+ bytes_mode == BYTES_B64));
- string jstype = JSTypeName(options, field);
+ string jstype = JSTypeName(options, field, bytes_mode);
if (field->is_repeated() &&
- !always_singular &&
(field->is_packed() || !singular_if_not_packed)) {
- if (!is_primitive) {
- jstype = "!" + jstype;
+ if (field->type() == FieldDescriptor::TYPE_BYTES &&
+ bytes_mode == BYTES_DEFAULT) {
+ jstype = "(Array<!Uint8Array>|Array<string>)";
+ } else {
+ if (!is_primitive) {
+ jstype = "!" + jstype;
+ }
+ jstype = "Array.<" + jstype + ">";
}
- jstype = "Array.<" + jstype + ">";
if (!force_optional) {
jstype = "!" + jstype;
}
@@ -884,10 +950,6 @@ string JSBinaryReaderMethodType(const FieldDescriptor* field) {
string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
bool is_writer) {
string name = JSBinaryReaderMethodType(field);
- if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) {
- // Override for `bytes` fields: treat string as raw bytes, not base64.
- name = "BytesRawString";
- }
if (field->is_packed()) {
name = "Packed" + name;
} else if (is_writer && field->is_repeated()) {
@@ -1044,7 +1106,7 @@ string FieldDefinition(const GeneratorOptions& options,
field->number());
}
-string FieldComments(const FieldDescriptor* field) {
+string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
string comments;
if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) {
comments +=
@@ -1060,6 +1122,11 @@ string FieldComments(const FieldDescriptor* field) {
" * replace the array itself, then you must call the setter to "
"update it.\n";
}
+ if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) {
+ comments +=
+ " * Note that Uint8Array is not supported on all browsers.\n"
+ " * @see http://caniuse.com/Uint8Array\n";
+ }
return comments;
}
@@ -1070,8 +1137,10 @@ bool ShouldGenerateExtension(const FieldDescriptor* field) {
}
bool HasExtensions(const Descriptor* desc) {
- if (desc->extension_count() > 0) {
- return true;
+ for (int i = 0; i < desc->extension_count(); i++) {
+ if (ShouldGenerateExtension(desc->extension(i))) {
+ return true;
+ }
}
for (int i = 0; i < desc->nested_type_count(); i++) {
if (HasExtensions(desc->nested_type(i))) {
@@ -1123,7 +1192,7 @@ string GetPivot(const Descriptor* desc) {
}
// Returns true for fields that represent "null" as distinct from the default
-// value. See https://go/proto3#heading=h.kozewqqcqhuz for more information.
+// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information.
bool HasFieldPresence(const FieldDescriptor* field) {
return
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
@@ -1132,7 +1201,7 @@ bool HasFieldPresence(const FieldDescriptor* field) {
}
// For proto3 fields without presence, returns a string representing the default
-// value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more
+// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more
// information.
string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
switch (field->cpp_type()) {
@@ -1151,16 +1220,153 @@ string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
case FieldDescriptor::CPPTYPE_BOOL:
return "false";
- case FieldDescriptor::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_STRING: // includes BYTES
return "\"\"";
default:
- // BYTES and MESSAGE are handled separately.
+ // MESSAGE is handled separately.
assert(false);
return "";
}
}
+// We use this to implement the semantics that same file can be generated
+// multiple times, but the last one wins. We never actually write the files,
+// but we keep a set of which descriptors were the final one for a given
+// filename.
+class FileDeduplicator {
+ public:
+ explicit FileDeduplicator(const GeneratorOptions& options)
+ : error_on_conflict_(options.error_on_name_conflict) {}
+
+ bool AddFile(const string& filename, const void* desc, string* error) {
+ if (descs_by_filename_.find(filename) != descs_by_filename_.end()) {
+ if (error_on_conflict_) {
+ *error = "Name conflict: file name " + filename +
+ " would be generated by two descriptors";
+ return false;
+ }
+ allowed_descs_.erase(descs_by_filename_[filename]);
+ }
+
+ descs_by_filename_[filename] = desc;
+ allowed_descs_.insert(desc);
+ return true;
+ }
+
+ void GetAllowedSet(set<const void*>* allowed_set) {
+ *allowed_set = allowed_descs_;
+ }
+
+ private:
+ bool error_on_conflict_;
+ map<string, const void*> descs_by_filename_;
+ set<const void*> allowed_descs_;
+};
+
+void DepthFirstSearch(const FileDescriptor* file,
+ vector<const FileDescriptor*>* list,
+ set<const FileDescriptor*>* seen) {
+ if (!seen->insert(file).second) {
+ return;
+ }
+
+ // Add all dependencies.
+ for (int i = 0; i < file->dependency_count(); i++) {
+ DepthFirstSearch(file->dependency(i), list, seen);
+ }
+
+ // Add this file.
+ list->push_back(file);
+}
+
+// A functor for the predicate to remove_if() below. Returns true if a given
+// FileDescriptor is not in the given set.
+class NotInSet {
+ public:
+ explicit NotInSet(const set<const FileDescriptor*>& file_set)
+ : file_set_(file_set) {}
+
+ bool operator()(const FileDescriptor* file) {
+ return file_set_.count(file) == 0;
+ }
+
+ private:
+ const set<const FileDescriptor*>& file_set_;
+};
+
+// This function generates an ordering of the input FileDescriptors that matches
+// the logic of the old code generator. The order is significant because two
+// different input files can generate the same output file, and the last one
+// needs to win.
+void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input,
+ vector<const FileDescriptor*>* ordered) {
+ // First generate an ordering of all reachable files (including dependencies)
+ // with depth-first search. This mimics the behavior of --include_imports,
+ // which is what the old codegen used.
+ ordered->clear();
+ set<const FileDescriptor*> seen;
+ set<const FileDescriptor*> input_set;
+ for (int i = 0; i < input.size(); i++) {
+ DepthFirstSearch(input[i], ordered, &seen);
+ input_set.insert(input[i]);
+ }
+
+ // Now remove the entries that are not actually in our input list.
+ ordered->erase(
+ std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)),
+ ordered->end());
+}
+
+// If we're generating code in file-per-type mode, avoid overwriting files
+// by choosing the last descriptor that writes each filename and permitting
+// only those to generate code.
+
+bool GenerateJspbAllowedSet(const GeneratorOptions& options,
+ const vector<const FileDescriptor*>& files,
+ set<const void*>* allowed_set,
+ string* error) {
+ vector<const FileDescriptor*> files_ordered;
+ GenerateJspbFileOrder(files, &files_ordered);
+
+ // Choose the last descriptor for each filename.
+ FileDeduplicator dedup(options);
+ for (int i = 0; i < files_ordered.size(); i++) {
+ for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
+ const Descriptor* desc = files_ordered[i]->message_type(j);
+ if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) {
+ return false;
+ }
+ }
+ for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
+ const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
+ if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) {
+ return false;
+ }
+ }
+
+ // Pull out all free-floating extensions and generate files for those too.
+ bool has_extension = false;
+
+ for (int j = 0; j < files_ordered[i]->extension_count(); j++) {
+ if (ShouldGenerateExtension(files_ordered[i]->extension(j))) {
+ has_extension = true;
+ }
+ }
+
+ if (has_extension) {
+ if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]),
+ files_ordered[i], error)) {
+ return false;
+ }
+ }
+ }
+
+ dedup.GetAllowedSet(allowed_set);
+
+ return true;
+}
+
} // anonymous namespace
void Generator::GenerateHeader(const GeneratorOptions& options,
@@ -1251,10 +1457,10 @@ void Generator::GenerateProvides(const GeneratorOptions& options,
}
}
-void Generator::GenerateRequires(const GeneratorOptions& options,
- io::Printer* printer,
- const Descriptor* desc,
- std::set<string>* provided) const {
+void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc,
+ std::set<string>* provided) const {
std::set<string> required;
std::set<string> forwards;
bool have_message = false;
@@ -1266,55 +1472,50 @@ void Generator::GenerateRequires(const GeneratorOptions& options,
/* require_extension = */ HasExtensions(desc));
}
-void Generator::GenerateRequires(const GeneratorOptions& options,
- io::Printer* printer,
- const vector<const FileDescriptor*>& files,
- std::set<string>* provided) const {
- if (options.import_style == GeneratorOptions::IMPORT_BROWSER) {
- return;
- } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
- // For Closure imports we need to import every message type individually.
- std::set<string> required;
- std::set<string> forwards;
- bool have_extensions = false;
- bool have_message = false;
+void Generator::GenerateRequiresForLibrary(
+ const GeneratorOptions& options, io::Printer* printer,
+ const vector<const FileDescriptor*>& files,
+ std::set<string>* provided) const {
+ GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE);
+ // For Closure imports we need to import every message type individually.
+ std::set<string> required;
+ std::set<string> forwards;
+ bool have_extensions = false;
+ bool have_message = false;
- for (int i = 0; i < files.size(); i++) {
- for (int j = 0; j < files[i]->message_type_count(); j++) {
- FindRequiresForMessage(options,
- files[i]->message_type(j),
- &required, &forwards, &have_message);
- }
- if (!have_extensions && HasExtensions(files[i])) {
- have_extensions = true;
- }
+ for (int i = 0; i < files.size(); i++) {
+ for (int j = 0; j < files[i]->message_type_count(); j++) {
+ FindRequiresForMessage(options,
+ files[i]->message_type(j),
+ &required, &forwards, &have_message);
+ }
+ if (!have_extensions && HasExtensions(files[i])) {
+ have_extensions = true;
+ }
- for (int j = 0; j < files[i]->extension_count(); j++) {
- const FieldDescriptor* extension = files[i]->extension(j);
- if (IgnoreField(extension)) {
- continue;
- }
- if (extension->containing_type()->full_name() !=
- "google.protobuf.bridge.MessageSet") {
- required.insert(GetPath(options, extension->containing_type()));
- }
- FindRequiresForField(options, extension, &required, &forwards);
- have_extensions = true;
+ for (int j = 0; j < files[i]->extension_count(); j++) {
+ const FieldDescriptor* extension = files[i]->extension(j);
+ if (IgnoreField(extension)) {
+ continue;
+ }
+ if (extension->containing_type()->full_name() !=
+ "google.protobuf.bridge.MessageSet") {
+ required.insert(GetPath(options, extension->containing_type()));
}
+ FindRequiresForField(options, extension, &required, &forwards);
+ have_extensions = true;
}
-
- GenerateRequiresImpl(options, printer, &required, &forwards, provided,
- /* require_jspb = */ have_message,
- /* require_extension = */ have_extensions);
- } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
- // CommonJS imports are based on files
}
+
+ GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+ /* require_jspb = */ have_message,
+ /* require_extension = */ have_extensions);
}
-void Generator::GenerateRequires(const GeneratorOptions& options,
- io::Printer* printer,
- const vector<const FieldDescriptor*>& fields,
- std::set<string>* provided) const {
+void Generator::GenerateRequiresForExtensions(
+ const GeneratorOptions& options, io::Printer* printer,
+ const vector<const FieldDescriptor*>& fields,
+ std::set<string>* provided) const {
std::set<string> required;
std::set<string> forwards;
for (int i = 0; i < fields.size(); i++) {
@@ -1741,17 +1942,34 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
}
} else {
// Simple field (singular or repeated).
- if (!HasFieldPresence(field) && !field->is_repeated()) {
+ if ((!HasFieldPresence(field) && !field->is_repeated()) ||
+ field->type() == FieldDescriptor::TYPE_BYTES) {
// Delegate to the generated get<field>() method in order not to duplicate
- // the proto3-field-default-value logic here.
+ // the proto3-field-default-value or byte-coercion logic here.
printer->Print("msg.get$getter$()",
- "getter", JSGetterName(field));
+ "getter", JSGetterName(field, BYTES_B64));
} else {
if (field->has_default_value()) {
- printer->Print("jspb.Message.getField(msg, $index$) != null ? "
- "jspb.Message.getField(msg, $index$) : $defaultValue$",
+ printer->Print("jspb.Message.getField(msg, $index$) == null ? "
+ "$defaultValue$ : ",
"index", JSFieldIndex(field),
"defaultValue", JSFieldDefault(field));
+ }
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+ if (field->is_repeated()) {
+ printer->Print("jspb.Message.getRepeatedFloatingPointField("
+ "msg, $index$)",
+ "index", JSFieldIndex(field));
+ } else if (field->is_optional() && !field->has_default_value()) {
+ printer->Print("jspb.Message.getOptionalFloatingPointField("
+ "msg, $index$)",
+ "index", JSFieldIndex(field));
+ } else {
+ // Convert "NaN" to NaN.
+ printer->Print("+jspb.Message.getField(msg, $index$)",
+ "index", JSFieldIndex(field));
+ }
} else {
printer->Print("jspb.Message.getField(msg, $index$)",
"index", JSFieldIndex(field));
@@ -1860,6 +2078,40 @@ void Generator::GenerateClassFields(const GeneratorOptions& options,
}
}
+void GenerateBytesWrapper(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field,
+ BytesMode bytes_mode) {
+ string type =
+ JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ false,
+ /* force_present = */ !HasFieldPresence(field),
+ /* singular_if_not_packed = */ false,
+ bytes_mode);
+ printer->Print(
+ "/**\n"
+ " * $fielddef$\n"
+ "$comment$"
+ " * This is a type-conversion wrapper around `get$defname$()`\n"
+ " * @return {$type$}\n"
+ " */\n"
+ "$class$.prototype.get$name$ = function() {\n"
+ " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n"
+ " this.get$defname$()));\n"
+ "};\n"
+ "\n"
+ "\n",
+ "fielddef", FieldDefinition(options, field),
+ "comment", FieldComments(field, bytes_mode),
+ "type", type,
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field, bytes_mode),
+ "list", field->is_repeated() ? "List" : "",
+ "suffix", JSByteGetterSuffix(bytes_mode),
+ "defname", JSGetterName(field, BYTES_DEFAULT));
+}
+
+
void Generator::GenerateClassField(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
@@ -1871,12 +2123,11 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
" * @return {$type$}\n"
" */\n",
"fielddef", FieldDefinition(options, field),
- "comment", FieldComments(field),
+ "comment", FieldComments(field, BYTES_DEFAULT),
"type", JSFieldTypeAnnotation(options, field,
/* force_optional = */ false,
/* force_present = */ false,
- /* singular_if_not_packed = */ false,
- /* always_singular = */ false));
+ /* singular_if_not_packed = */ false));
printer->Print(
"$class$.prototype.get$name$ = function() {\n"
" return /** @type{$type$} */ (\n"
@@ -1890,8 +2141,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"type", JSFieldTypeAnnotation(options, field,
/* force_optional = */ false,
/* force_present = */ false,
- /* singular_if_not_packed = */ false,
- /* always_singular = */ false),
+ /* singular_if_not_packed = */ false),
"rpt", (field->is_repeated() ? "Repeated" : ""),
"index", JSFieldIndex(field),
"wrapperclass", SubmessageTypeRef(options, field),
@@ -1905,8 +2155,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
JSFieldTypeAnnotation(options, field,
/* force_optional = */ true,
/* force_present = */ false,
- /* singular_if_not_packed = */ false,
- /* always_singular = */ false),
+ /* singular_if_not_packed = */ false),
"returndoc", JSReturnDoc(options, field),
"class", GetPath(options, field->containing_type()),
"name", JSGetterName(field),
@@ -1935,15 +2184,29 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"returnvalue", JSReturnClause(field));
} else {
- string typed_annotation;
+ bool untyped =
+ false;
// Simple (primitive) field, either singular or repeated.
- {
- typed_annotation = JSFieldTypeAnnotation(options, field,
+
+ // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type;
+ // at this point we "lie" to non-binary users and tell the the return
+ // type is always base64 string, pending a LSC to migrate to typed getters.
+ BytesMode bytes_mode =
+ field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ?
+ BYTES_B64 : BYTES_DEFAULT;
+ string typed_annotation =
+ JSFieldTypeAnnotation(options, field,
/* force_optional = */ false,
/* force_present = */ !HasFieldPresence(field),
/* singular_if_not_packed = */ false,
- /* always_singular = */ false),
+ /* bytes_mode = */ bytes_mode);
+ if (untyped) {
+ printer->Print(
+ "/**\n"
+ " * @return {?} Raw field, untyped.\n"
+ " */\n");
+ } else {
printer->Print(
"/**\n"
" * $fielddef$\n"
@@ -1951,7 +2214,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
" * @return {$type$}\n"
" */\n",
"fielddef", FieldDefinition(options, field),
- "comment", FieldComments(field),
+ "comment", FieldComments(field, bytes_mode),
"type", typed_annotation);
}
@@ -1960,7 +2223,10 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"class", GetPath(options, field->containing_type()),
"name", JSGetterName(field));
- {
+ if (untyped) {
+ printer->Print(
+ " return ");
+ } else {
printer->Print(
" return /** @type {$type$} */ (",
"type", typed_annotation);
@@ -1975,17 +2241,39 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"default", Proto3PrimitiveFieldDefault(field));
} else {
if (field->has_default_value()) {
- printer->Print("jspb.Message.getField(this, $index$) != null ? "
- "jspb.Message.getField(this, $index$) : $defaultValue$",
+ printer->Print("jspb.Message.getField(this, $index$) == null ? "
+ "$defaultValue$ : ",
"index", JSFieldIndex(field),
"defaultValue", JSFieldDefault(field));
+ }
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+ if (field->is_repeated()) {
+ printer->Print("jspb.Message.getRepeatedFloatingPointField("
+ "this, $index$)",
+ "index", JSFieldIndex(field));
+ } else if (field->is_optional() && !field->has_default_value()) {
+ printer->Print("jspb.Message.getOptionalFloatingPointField("
+ "this, $index$)",
+ "index", JSFieldIndex(field));
+ } else {
+ // Convert "NaN" to NaN.
+ printer->Print("+jspb.Message.getField(this, $index$)",
+ "index", JSFieldIndex(field));
+ }
} else {
printer->Print("jspb.Message.getField(this, $index$)",
"index", JSFieldIndex(field));
}
}
- {
+ if (untyped) {
+ printer->Print(
+ ";\n"
+ "};\n"
+ "\n"
+ "\n");
+ } else {
printer->Print(
");\n"
"};\n"
@@ -1993,18 +2281,27 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"\n");
}
- {
+ if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) {
+ GenerateBytesWrapper(options, printer, field, BYTES_B64);
+ GenerateBytesWrapper(options, printer, field, BYTES_U8);
+ }
+
+ if (untyped) {
+ printer->Print(
+ "/**\n"
+ " * @param {*} value $returndoc$\n"
+ " */\n",
+ "returndoc", JSReturnDoc(options, field));
+ } else {
printer->Print(
"/** @param {$optionaltype$} value $returndoc$ */\n",
"optionaltype",
JSFieldTypeAnnotation(options, field,
/* force_optional = */ true,
/* force_present = */ !HasFieldPresence(field),
- /* singular_if_not_packed = */ false,
- /* always_singular = */ false),
+ /* singular_if_not_packed = */ false),
"returndoc", JSReturnDoc(options, field));
}
-
printer->Print(
"$class$.prototype.set$name$ = function(value) {\n"
" jspb.Message.set$oneoftag$Field(this, $index$",
@@ -2017,14 +2314,22 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"};\n"
"\n"
"\n",
- "type", "",
- "typeclose", "",
+ "type",
+ untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "",
+ "typeclose", untyped ? ")" : "",
"oneofgroup",
(field->containing_oneof() ? (", " + JSOneofArray(options, field))
: ""),
"returnvalue", JSReturnClause(field), "rptvalueinit",
(field->is_repeated() ? " || []" : ""));
+ if (untyped) {
+ printer->Print(
+ "/**\n"
+ " * Clears the value. $returndoc$\n"
+ " */\n",
+ "returndoc", JSReturnDoc(options, field));
+ }
if (HasFieldPresence(field)) {
printer->Print(
@@ -2162,16 +2467,18 @@ void Generator::GenerateClassDeserializeBinaryField(
" var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
"fieldtype", JSFieldTypeAnnotation(options, field, false, true,
/* singular_if_not_packed = */ true,
- /* always_singular = */ false),
+ BYTES_U8),
"reader", JSBinaryReaderMethodName(field));
}
if (field->is_repeated() && !field->is_packed()) {
// Repeated fields receive a |value| one at at a time; append to array
- // returned by get$name$().
- printer->Print(
- " msg.get$name$().push(value);\n",
- "name", JSGetterName(field));
+ // returned by get$name$(). Annoyingly, we have to call 'set' after
+ // changing the array.
+ printer->Print(" msg.get$name$().push(value);\n", "name",
+ JSGetterName(field));
+ printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
+ JSGetterName(field));
} else {
// Singular fields, and packed repeated fields, receive a |value| either as
// the field's value or as the array of all the field's values; set this as
@@ -2244,7 +2551,7 @@ void Generator::GenerateClassSerializeBinaryField(
const FieldDescriptor* field) const {
printer->Print(
" f = this.get$name$();\n",
- "name", JSGetterName(field));
+ "name", JSGetterName(field, BYTES_U8));
if (field->is_repeated()) {
printer->Print(
@@ -2294,7 +2601,6 @@ void Generator::GenerateClassSerializeBinaryField(
" $index$,\n"
" f",
"writer", JSBinaryWriterMethodName(field),
- "name", JSGetterName(field),
"index", SimpleItoa(field->number()));
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
@@ -2356,8 +2662,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
options, field,
/* force_optional = */ false,
/* force_present = */ true,
- /* singular_if_not_packed = */ false,
- /* always_singular = */ false));
+ /* singular_if_not_packed = */ false));
printer->Print(
" $index$,\n"
" {$name$: 0},\n"
@@ -2528,7 +2833,7 @@ void Generator::GenerateFile(const GeneratorOptions& options,
printer->Print("var global = Function('return this')();\n\n");
for (int i = 0; i < file->dependency_count(); i++) {
- const std::string& name = file->dependency(i)->name();
+ const string& name = file->dependency(i)->name();
printer->Print(
"var $alias$ = require('$file$');\n",
"alias", ModuleAlias(name),
@@ -2543,7 +2848,7 @@ void Generator::GenerateFile(const GeneratorOptions& options,
//
// // Later generated code expects foo.bar = {} to exist:
// foo.bar.Baz = function() { /* ... */ }
- std::set<std::string> provided;
+ set<string> provided;
// Cover the case where this file declares extensions but no messages.
// This will ensure that the file-level object will be declared to hold
@@ -2615,7 +2920,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
FindProvidesForFields(options, &printer, extensions, &provided);
GenerateProvides(options, &printer, &provided);
GenerateTestOnly(options, &printer);
- GenerateRequires(options, &printer, files, &provided);
+ GenerateRequiresForLibrary(options, &printer, files, &provided);
GenerateFilesInDepOrder(options, &printer, files);
@@ -2629,66 +2934,20 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
return false;
}
} else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
- // Collect all types, and print each type to a separate file. Pull out
- // free-floating extensions while we make this pass.
- map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
-
- // If we're generating code in file-per-type mode, avoid overwriting files
- // by choosing the last descriptor that writes each filename and permitting
- // only those to generate code.
-
- // Current descriptor that will generate each filename, indexed by filename.
- map<string, const void*> desc_by_filename;
- // Set of descriptors allowed to generate files.
- set<const void*> allowed_descs;
-
- for (int i = 0; i < files.size(); i++) {
- // Collect all (descriptor, filename) pairs.
- map<const void*, string> descs_in_file;
- for (int j = 0; j < files[i]->message_type_count(); j++) {
- const Descriptor* desc = files[i]->message_type(j);
- string filename =
- options.output_dir + "/" + ToFileName(desc->name()) + ".js";
- descs_in_file[desc] = filename;
- }
- for (int j = 0; j < files[i]->enum_type_count(); j++) {
- const EnumDescriptor* desc = files[i]->enum_type(j);
- string filename =
- options.output_dir + "/" + ToFileName(desc->name()) + ".js";
- descs_in_file[desc] = filename;
- }
-
- // For each (descriptor, filename) pair, update the
- // descriptors-by-filename map, and if a previous descriptor was already
- // writing the filename, remove it from the allowed-descriptors set.
- map<const void*, string>::iterator it;
- for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) {
- const void* desc = it->first;
- const string& filename = it->second;
- if (desc_by_filename.find(filename) != desc_by_filename.end()) {
- if (options.error_on_name_conflict) {
- *error = "Name conflict: file name " + filename +
- " would be generated by two descriptors";
- return false;
- }
- allowed_descs.erase(desc_by_filename[filename]);
- }
- desc_by_filename[filename] = desc;
- allowed_descs.insert(desc);
- }
+ set<const void*> allowed_set;
+ if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
+ return false;
}
- // Generate code.
for (int i = 0; i < files.size(); i++) {
const FileDescriptor* file = files[i];
for (int j = 0; j < file->message_type_count(); j++) {
const Descriptor* desc = file->message_type(j);
- if (allowed_descs.find(desc) == allowed_descs.end()) {
+ if (allowed_set.count(desc) == 0) {
continue;
}
- string filename = options.output_dir + "/" +
- ToFileName(desc->name()) + ".js";
+ string filename = GetMessageFileName(options, desc);
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
context->Open(filename));
GOOGLE_CHECK(output.get());
@@ -2700,7 +2959,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
FindProvidesForMessage(options, &printer, desc, &provided);
GenerateProvides(options, &printer, &provided);
GenerateTestOnly(options, &printer);
- GenerateRequires(options, &printer, desc, &provided);
+ GenerateRequiresForMessage(options, &printer, desc, &provided);
GenerateClass(options, &printer, desc);
@@ -2710,13 +2969,11 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
}
for (int j = 0; j < file->enum_type_count(); j++) {
const EnumDescriptor* enumdesc = file->enum_type(j);
- if (allowed_descs.find(enumdesc) == allowed_descs.end()) {
+ if (allowed_set.count(enumdesc) == 0) {
continue;
}
- string filename = options.output_dir + "/" +
- ToFileName(enumdesc->name()) + ".js";
-
+ string filename = GetEnumFileName(options, enumdesc);
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
context->Open(filename));
GOOGLE_CHECK(output.get());
@@ -2735,38 +2992,36 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
return false;
}
}
- // Pull out all free-floating extensions and generate files for those too.
- for (int j = 0; j < file->extension_count(); j++) {
- const FieldDescriptor* extension = file->extension(j);
- extensions_by_namespace[GetPath(options, files[i])]
- .push_back(extension);
- }
- }
+ // File-level extensions (message-level extensions are generated under
+ // the enclosing message).
+ if (allowed_set.count(file) == 1) {
+ string filename = GetExtensionFileName(options, file);
- // Generate extensions in separate files.
- map< string, vector<const FieldDescriptor*> >::iterator it;
- for (it = extensions_by_namespace.begin();
- it != extensions_by_namespace.end();
- ++it) {
- string filename = options.output_dir + "/" +
- ToFileName(it->first) + ".js";
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filename));
+ GOOGLE_CHECK(output.get());
+ io::Printer printer(output.get(), '$');
- google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
- context->Open(filename));
- GOOGLE_CHECK(output.get());
- io::Printer printer(output.get(), '$');
+ GenerateHeader(options, &printer);
+
+ std::set<string> provided;
+ vector<const FieldDescriptor*> fields;
- GenerateHeader(options, &printer);
+ for (int j = 0; j < files[i]->extension_count(); j++) {
+ if (ShouldGenerateExtension(files[i]->extension(j))) {
+ fields.push_back(files[i]->extension(j));
+ }
+ }
- std::set<string> provided;
- FindProvidesForFields(options, &printer, it->second, &provided);
- GenerateProvides(options, &printer, &provided);
- GenerateTestOnly(options, &printer);
- GenerateRequires(options, &printer, it->second, &provided);
+ FindProvidesForFields(options, &printer, fields, &provided);
+ GenerateProvides(options, &printer, &provided);
+ GenerateTestOnly(options, &printer);
+ GenerateRequiresForExtensions(options, &printer, fields, &provided);
- for (int j = 0; j < it->second.size(); j++) {
- if (ShouldGenerateExtension(it->second[j])) {
- GenerateExtension(options, &printer, it->second[j]);
+ for (int j = 0; j < files[i]->extension_count(); j++) {
+ if (ShouldGenerateExtension(files[i]->extension(j))) {
+ GenerateExtension(options, &printer, files[i]->extension(j));
+ }
}
}
}
@@ -2777,7 +3032,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
const google::protobuf::FileDescriptor* file = files[i];
string filename = options.output_dir + "/" + GetJSFilename(file->name());
- google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ scoped_ptr<io::ZeroCopyOutputStream> output(
context->Open(filename));
GOOGLE_CHECK(output.get());
io::Printer printer(output.get(), '$');
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
index db9178d3..6fd7ca50 100755
--- a/src/google/protobuf/compiler/js/js_generator.h
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -146,19 +146,19 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
io::Printer* printer) const;
// Generate goog.requires() calls.
- void GenerateRequires(const GeneratorOptions& options,
- io::Printer* printer,
- const vector<const FileDescriptor*>& file,
- std::set<string>* provided) const;
- void GenerateRequires(const GeneratorOptions& options,
+ void GenerateRequiresForLibrary(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& files,
+ std::set<string>* provided) const;
+ void GenerateRequiresForMessage(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc,
std::set<string>* provided) const;
// For extension fields at file scope.
- void GenerateRequires(const GeneratorOptions& options,
- io::Printer* printer,
- const vector<const FieldDescriptor*>& fields,
- std::set<string>* provided) const;
+ void GenerateRequiresForExtensions(
+ const GeneratorOptions& options, io::Printer* printer,
+ const vector<const FieldDescriptor*>& fields,
+ std::set<string>* provided) const;
void GenerateRequiresImpl(const GeneratorOptions& options,
io::Printer* printer,
std::set<string>* required,
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 121d917b..82bb3427 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -32,20 +32,26 @@
#include <google/protobuf/compiler/mock_code_generator.h>
+#include <stdlib.h>
+#include <iostream>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
+#include <vector>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 8c8348d8..e1665f88 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -34,10 +34,15 @@
#define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
#include <string>
+
#include <google/protobuf/compiler/code_generator.h>
namespace google {
namespace protobuf {
+class FileDescriptor;
+} // namespace protobuf
+
+namespace protobuf {
namespace compiler {
// A mock CodeGenerator, used by command_line_interface_unittest. This is in
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index 2bebf1f3..2ff50f61 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -93,31 +93,15 @@ class GeneratorResponseContext : public GeneratorContext {
const vector<const FileDescriptor*>& parsed_files_;
};
-int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
-
- if (argc > 1) {
- std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
- return 1;
- }
-
-#ifdef _WIN32
- _setmode(STDIN_FILENO, _O_BINARY);
- _setmode(STDOUT_FILENO, _O_BINARY);
-#endif
-
- CodeGeneratorRequest request;
- if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
- std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
- << std::endl;
- return 1;
- }
-
+bool GenerateCode(const CodeGeneratorRequest& request,
+ const CodeGenerator& generator, CodeGeneratorResponse* response,
+ string* error_msg) {
DescriptorPool pool;
for (int i = 0; i < request.proto_file_size(); i++) {
const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
if (file == NULL) {
// BuildFile() already wrote an error message.
- return 1;
+ return false;
}
}
@@ -125,19 +109,18 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
for (int i = 0; i < request.file_to_generate_size(); i++) {
parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
if (parsed_files.back() == NULL) {
- std::cerr << argv[0] << ": protoc asked plugin to generate a file but "
- "did not provide a descriptor for the file: "
- << request.file_to_generate(i) << std::endl;
- return 1;
+ *error_msg = "protoc asked plugin to generate a file but "
+ "did not provide a descriptor for the file: " +
+ request.file_to_generate(i);
+ return false;
}
}
- CodeGeneratorResponse response;
- GeneratorResponseContext context(&response, parsed_files);
+ GeneratorResponseContext context(response, parsed_files);
- if (generator->HasGenerateAll()) {
+ if (generator.HasGenerateAll()) {
string error;
- bool succeeded = generator->GenerateAll(
+ bool succeeded = generator.GenerateAll(
parsed_files, request.parameter(), &context, &error);
if (!succeeded && error.empty()) {
@@ -145,14 +128,14 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
"description.";
}
if (!error.empty()) {
- response.set_error(error);
+ response->set_error(error);
}
} else {
for (int i = 0; i < parsed_files.size(); i++) {
const FileDescriptor* file = parsed_files[i];
string error;
- bool succeeded = generator->Generate(
+ bool succeeded = generator.Generate(
file, request.parameter(), &context, &error);
if (!succeeded && error.empty()) {
@@ -160,14 +143,46 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
"description.";
}
if (!error.empty()) {
- response.set_error(file->name() + ": " + error);
+ response->set_error(file->name() + ": " + error);
break;
}
}
}
- if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
- std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
+ return true;
+}
+
+int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
+
+ if (argc > 1) {
+ std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
+ return 1;
+ }
+
+#ifdef _WIN32
+ _setmode(STDIN_FILENO, _O_BINARY);
+ _setmode(STDOUT_FILENO, _O_BINARY);
+#endif
+
+ CodeGeneratorRequest request;
+ if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
+ std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
+ << std::endl;
+ return 1;
+ }
+
+ string error_msg;
+ CodeGeneratorResponse response;
+
+ if (GenerateCode(request, *generator, &response, &error_msg)) {
+ if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
+ std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
+ return 1;
+ }
+ } else {
+ if (!error_msg.empty()) {
+ std::cerr << argv[0] << ": " << error_msg << std::endl;
+ }
return 1;
}
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 679f9bdb..d2793a9f 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -40,6 +40,13 @@
// }
// You must link your plugin against libprotobuf and libprotoc.
//
+// The core part of PluginMain is to invoke the given CodeGenerator on a
+// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is
+// abstracted out and made into function GenerateCode so that it can be reused,
+// for example, to implement a variant of PluginMain that does some
+// preprocessing on the input CodeGeneratorRequest before feeding the request
+// to the given code generator.
+//
// To get protoc to use the plugin, do one of the following:
// * Place the plugin binary somewhere in the PATH and give it the name
// "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you
@@ -55,16 +62,27 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
+#include <string>
+
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace compiler {
class CodeGenerator; // code_generator.h
+class CodeGeneratorRequest;
+class CodeGeneratorResponse;
// Implements main() for a protoc plugin exposing the given code generator.
LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
+// Generates code using the given code generator. Returns true if the code
+// generation is successful. If the code geneartion fails, error_msg may be
+// populated to describe the failure cause.
+bool GenerateCode(const CodeGeneratorRequest& request,
+ const CodeGenerator& generator, CodeGeneratorResponse* response,
+ string* error_msg);
+
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 4d500f90..0553dd0d 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -235,7 +235,7 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
// infinity * 0 = nan
return "(1e10000 * 0)";
} else {
- return SimpleDtoa(value);
+ return "float(" + SimpleDtoa(value) + ")";
}
}
case FieldDescriptor::CPPTYPE_FLOAT: {
@@ -251,7 +251,7 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
// infinity - infinity = nan
return "(1e10000 * 0)";
} else {
- return SimpleFtoa(value);
+ return "float(" + SimpleFtoa(value) + ")";
}
}
case FieldDescriptor::CPPTYPE_BOOL:
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index a30ac305..6e258664 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -361,7 +361,7 @@ bool Subprocess::Communicate(const Message& input, Message* output,
string output_data;
int input_pos = 0;
- int max_fd = max(child_stdin_, child_stdout_);
+ int max_fd = std::max(child_stdin_, child_stdout_);
while (child_stdout_ != -1) {
fd_set read_fds;