Index: third_party/protobuf/src/google/protobuf/compiler/ruby/ruby_generator.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/ruby/ruby_generator.cc b/third_party/protobuf/src/google/protobuf/compiler/ruby/ruby_generator.cc |
index 9692f1bff51c76f5fc29c756797fc57c9425db43..92c76fb0364bc3cad114ae5805996b3274c9f218 100644 |
--- a/third_party/protobuf/src/google/protobuf/compiler/ruby/ruby_generator.cc |
+++ b/third_party/protobuf/src/google/protobuf/compiler/ruby/ruby_generator.cc |
@@ -75,6 +75,10 @@ std::string StripDotProto(const std::string& proto_file) { |
return proto_file.substr(0, lastindex); |
} |
+std::string GetOutputFilename(const std::string& proto_file) { |
+ return StripDotProto(proto_file) + ".rb"; |
+} |
+ |
std::string LabelForField(const google::protobuf::FieldDescriptor* field) { |
switch (field->label()) { |
case FieldDescriptor::LABEL_OPTIONAL: return "optional"; |
@@ -331,8 +335,69 @@ void EndPackageModules( |
} |
} |
-void GenerateFile(const google::protobuf::FileDescriptor* file, |
- google::protobuf::io::Printer* printer) { |
+bool UsesTypeFromFile(const Descriptor* message, const FileDescriptor* file, |
+ string* error) { |
+ for (int i = 0; i < message->field_count(); i++) { |
+ const FieldDescriptor* field = message->field(i); |
+ if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
+ field->message_type()->file() == file) || |
+ (field->type() == FieldDescriptor::TYPE_ENUM && |
+ field->enum_type()->file() == file)) { |
+ *error = "proto3 message field " + field->full_name() + " in file " + |
+ file->name() + " has a dependency on a type from proto2 file " + |
+ file->name() + |
+ ". Ruby doesn't support proto2 yet, so we must fail."; |
+ return true; |
+ } |
+ } |
+ |
+ for (int i = 0; i < message->nested_type_count(); i++) { |
+ if (UsesTypeFromFile(message->nested_type(i), file, error)) { |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+// Ruby doesn't currently support proto2. This causes a failure even for proto3 |
+// files that import proto2. But in some cases, the proto2 file is only being |
+// imported to extend another proto2 message. The prime example is declaring |
+// custom options by extending FileOptions/FieldOptions/etc. |
+// |
+// If the proto3 messages don't have any proto2 submessages, it is safe to omit |
+// the dependency completely. Users won't be able to use any proto2 extensions, |
+// but they already couldn't because proto2 messages aren't supported. |
+// |
+// If/when we add proto2 support, we should remove this. |
+bool MaybeEmitDependency(const FileDescriptor* import, |
+ const FileDescriptor* from, |
+ io::Printer* printer, |
+ string* error) { |
+ if (import->syntax() == FileDescriptor::SYNTAX_PROTO2) { |
+ for (int i = 0; i < from->message_type_count(); i++) { |
+ if (UsesTypeFromFile(from->message_type(i), import, error)) { |
+ // Error text was already set by UsesTypeFromFile(). |
+ return false; |
+ } |
+ } |
+ |
+ // Ok to omit this proto2 dependency -- so we won't print anything. |
+ GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() |
+ << "' from proto3 output file '" |
+ << GetOutputFilename(from->name()) |
+ << "' because we don't support proto2 and no proto2 " |
+ "types from that file are being used."; |
+ return true; |
+ } else { |
+ printer->Print( |
+ "require '$name$'\n", "name", StripDotProto(import->name())); |
+ return true; |
+ } |
+} |
+ |
+bool GenerateFile(const FileDescriptor* file, io::Printer* printer, |
+ string* error) { |
printer->Print( |
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
"# source: $filename$\n" |
@@ -343,9 +408,9 @@ void GenerateFile(const google::protobuf::FileDescriptor* file, |
"require 'google/protobuf'\n\n"); |
for (int i = 0; i < file->dependency_count(); i++) { |
- const std::string& name = file->dependency(i)->name(); |
- printer->Print( |
- "require '$name$'\n", "name", StripDotProto(name)); |
+ if (!MaybeEmitDependency(file->dependency(i), file, printer, error)) { |
+ return false; |
+ } |
} |
printer->Print( |
@@ -369,6 +434,7 @@ void GenerateFile(const google::protobuf::FileDescriptor* file, |
GenerateEnumAssignment("", file->enum_type(i), printer); |
} |
EndPackageModules(levels, printer); |
+ return true; |
} |
bool Generator::Generate( |
@@ -384,15 +450,11 @@ bool Generator::Generate( |
return false; |
} |
- std::string filename = |
- StripDotProto(file->name()) + ".rb"; |
scoped_ptr<io::ZeroCopyOutputStream> output( |
- generator_context->Open(filename)); |
+ generator_context->Open(GetOutputFilename(file->name()))); |
io::Printer printer(output.get(), '$'); |
- GenerateFile(file, &printer); |
- |
- return true; |
+ return GenerateFile(file, &printer, error); |
} |
} // namespace ruby |