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