diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/google/protobuf/compiler/ruby/ruby_generator.cc | 91 | ||||
-rw-r--r-- | src/google/protobuf/compiler/ruby/ruby_generator.h | 3 | ||||
-rw-r--r-- | src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc | 119 | ||||
-rw-r--r-- | src/google/protobuf/stubs/atomicops_internals_mips_gcc.h | 4 |
5 files changed, 205 insertions, 13 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index fc0d70e7..0f0bd089 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -460,6 +460,7 @@ protobuf_test_SOURCES = \ google/protobuf/compiler/java/java_plugin_unittest.cc \ google/protobuf/compiler/java/java_doc_comment_unittest.cc \ google/protobuf/compiler/python/python_plugin_unittest.cc \ + google/protobuf/compiler/ruby/ruby_generator_unittest.cc \ $(COMMON_TEST_SOURCES) nodist_protobuf_test_SOURCES = $(protoc_outputs) diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc index c5687903..88292891 100644 --- a/src/google/protobuf/compiler/ruby/ruby_generator.cc +++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc @@ -47,7 +47,7 @@ namespace compiler { namespace ruby { // Forward decls. -std::string IntToString(uint32_t value); +std::string IntToString(uint32 value); std::string StripDotProto(const std::string& proto_file); std::string LabelForField(google::protobuf::FieldDescriptor* field); std::string TypeName(google::protobuf::FieldDescriptor* field); @@ -64,7 +64,7 @@ void GenerateEnumAssignment( const google::protobuf::EnumDescriptor* en, google::protobuf::io::Printer* printer); -std::string IntToString(uint32_t value) { +std::string IntToString(uint32 value) { std::ostringstream os; os << value; return os.str(); @@ -100,15 +100,35 @@ std::string TypeName(const google::protobuf::FieldDescriptor* field) { } } -void GenerateMessage(const google::protobuf::Descriptor* message, - google::protobuf::io::Printer* printer) { - printer->Print( - "add_message \"$name$\" do\n", - "name", message->full_name()); - printer->Indent(); +void GenerateField(const google::protobuf::FieldDescriptor* field, + google::protobuf::io::Printer* printer) { + + if (field->is_map()) { + const FieldDescriptor* key_field = + field->message_type()->FindFieldByNumber(1); + const FieldDescriptor* value_field = + field->message_type()->FindFieldByNumber(2); + + printer->Print( + "map :$name$, :$key_type$, :$value_type$, $number$", + "name", field->name(), + "key_type", TypeName(key_field), + "value_type", TypeName(value_field), + "number", IntToString(field->number())); + + if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ", \"$subtype$\"\n", + "subtype", value_field->message_type()->full_name()); + } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + ", \"$subtype$\"\n", + "subtype", value_field->enum_type()->full_name()); + } else { + printer->Print("\n"); + } + } else { - for (int i = 0; i < message->field_count(); i++) { - const FieldDescriptor* field = message->field(i); printer->Print( "$label$ :$name$, ", "label", LabelForField(field), @@ -117,6 +137,7 @@ void GenerateMessage(const google::protobuf::Descriptor* message, ":$type$, $number$", "type", TypeName(field), "number", IntToString(field->number())); + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { printer->Print( ", \"$subtype$\"\n", @@ -129,6 +150,49 @@ void GenerateMessage(const google::protobuf::Descriptor* message, printer->Print("\n"); } } +} + +void GenerateOneof(const google::protobuf::OneofDescriptor* oneof, + google::protobuf::io::Printer* printer) { + printer->Print( + "oneof :$name$ do\n", + "name", oneof->name()); + printer->Indent(); + + for (int i = 0; i < oneof->field_count(); i++) { + const FieldDescriptor* field = oneof->field(i); + GenerateField(field, printer); + } + + printer->Outdent(); + printer->Print("end\n"); +} + +void GenerateMessage(const google::protobuf::Descriptor* message, + google::protobuf::io::Printer* printer) { + + // Don't generate MapEntry messages -- we use the Ruby extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + + printer->Print( + "add_message \"$name$\" do\n", + "name", message->full_name()); + printer->Indent(); + + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + if (!field->containing_oneof()) { + GenerateField(field, printer); + } + } + + for (int i = 0; i < message->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + GenerateOneof(oneof, printer); + } printer->Outdent(); printer->Print("end\n"); @@ -185,6 +249,13 @@ void GenerateMessageAssignment( const std::string& prefix, const google::protobuf::Descriptor* message, google::protobuf::io::Printer* printer) { + + // Don't generate MapEntry messages -- we use the Ruby extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + printer->Print( "$prefix$$name$ = ", "prefix", prefix, diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.h b/src/google/protobuf/compiler/ruby/ruby_generator.h index 48dbefd1..75555c31 100644 --- a/src/google/protobuf/compiler/ruby/ruby_generator.h +++ b/src/google/protobuf/compiler/ruby/ruby_generator.h @@ -40,7 +40,8 @@ namespace protobuf { namespace compiler { namespace ruby { -class Generator : public google::protobuf::compiler::CodeGenerator { +class LIBPROTOC_EXPORT Generator + : public google::protobuf::compiler::CodeGenerator { virtual bool Generate( const FileDescriptor* file, const string& parameter, diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc new file mode 100644 index 00000000..e35ca695 --- /dev/null +++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc @@ -0,0 +1,119 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <memory> + +#include <google/protobuf/compiler/ruby/ruby_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/printer.h> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace ruby { +namespace { + +string FindRubyTestDir() { + // Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc. + string prefix = "."; + while (!File::Exists(prefix + "/ruby/tests")) { + if (!File::Exists(prefix)) { + GOOGLE_LOG(FATAL) + << "Could not find Ruby test directory. Please run tests from " + "somewhere within the protobuf source package."; + } + prefix += "/.."; + } + return prefix + "/ruby/tests"; +} + +// This test is a simple golden-file test over the output of the Ruby code +// generator. When we make changes to the Ruby extension and alter the Ruby code +// generator to use those changes, we should (i) manually test the output of the +// code generator with the extension, and (ii) update the golden output above. +// Some day, we may integrate build systems between protoc and the language +// extensions to the point where we can do this test in a more automated way. + +TEST(RubyGeneratorTest, GeneratorTest) { + string ruby_tests = FindRubyTestDir(); + + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + ruby::Generator ruby_generator; + cli.RegisterGenerator("--ruby_out", &ruby_generator, ""); + + // Copy generated_code.proto to the temporary test directory. + string test_input; + GOOGLE_CHECK_OK(File::GetContents( + ruby_tests + "/generated_code.proto", + &test_input, + true)); + GOOGLE_CHECK_OK(File::SetContents( + TestTempDir() + "/generated_code.proto", + test_input, + true)); + + // Invoke the proto compiler (we will be inside TestTempDir() at this point). + string ruby_out = "--ruby_out=" + TestTempDir(); + string proto_path = "--proto_path=" + TestTempDir(); + const char* argv[] = { + "protoc", + ruby_out.c_str(), + proto_path.c_str(), + "generated_code.proto", + }; + + EXPECT_EQ(0, cli.Run(4, argv)); + + // Load the generated output and compare to the expected result. + string output; + GOOGLE_CHECK_OK(File::GetContents( + TestTempDir() + "/generated_code.rb", + &output, + true)); + string expected_output; + GOOGLE_CHECK_OK(File::GetContents( + ruby_tests + "/generated_code.rb", + &expected_output, + true)); + EXPECT_EQ(expected_output, output); +} + +} // namespace +} // namespace ruby +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h b/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h index e3cd14cf..f5837c9e 100644 --- a/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h +++ b/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h @@ -65,7 +65,7 @@ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, "2:\n" ".set pop\n" : "=&r" (prev), "=m" (*ptr), "=&r" (tmp) - : "Ir" (old_value), "r" (new_value), "m" (*ptr) + : "r" (old_value), "r" (new_value), "m" (*ptr) : "memory"); return prev; } @@ -197,7 +197,7 @@ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, "2:\n" ".set pop\n" : "=&r" (prev), "=m" (*ptr), "=&r" (tmp) - : "Ir" (old_value), "r" (new_value), "m" (*ptr) + : "r" (old_value), "r" (new_value), "m" (*ptr) : "memory"); return prev; } |