LCOV - code coverage report
Current view: top level - third_party/protobuf/src/google/protobuf/compiler/ruby - ruby_generator.cc (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 0 161 0.0 %
Date: 2015-10-10 Functions: 0 15 0.0 %

          Line data    Source code
       1             : // Protocol Buffers - Google's data interchange format
       2             : // Copyright 2008 Google Inc.  All rights reserved.
       3             : // https://developers.google.com/protocol-buffers/
       4             : //
       5             : // Redistribution and use in source and binary forms, with or without
       6             : // modification, are permitted provided that the following conditions are
       7             : // met:
       8             : //
       9             : //     * Redistributions of source code must retain the above copyright
      10             : // notice, this list of conditions and the following disclaimer.
      11             : //     * Redistributions in binary form must reproduce the above
      12             : // copyright notice, this list of conditions and the following disclaimer
      13             : // in the documentation and/or other materials provided with the
      14             : // distribution.
      15             : //     * Neither the name of Google Inc. nor the names of its
      16             : // contributors may be used to endorse or promote products derived from
      17             : // this software without specific prior written permission.
      18             : //
      19             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      22             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      23             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      24             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      25             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      29             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             : 
      31             : #include <sstream>
      32             : 
      33             : #include <google/protobuf/compiler/code_generator.h>
      34             : #include <google/protobuf/compiler/plugin.h>
      35             : #include <google/protobuf/descriptor.h>
      36             : #include <google/protobuf/descriptor.pb.h>
      37             : #include <google/protobuf/io/printer.h>
      38             : #include <google/protobuf/io/zero_copy_stream.h>
      39             : 
      40             : #include <google/protobuf/compiler/ruby/ruby_generator.h>
      41             : 
      42             : using google::protobuf::internal::scoped_ptr;
      43             : 
      44             : namespace google {
      45             : namespace protobuf {
      46             : namespace compiler {
      47             : namespace ruby {
      48             : 
      49             : // Forward decls.
      50             : std::string IntToString(int32 value);
      51             : std::string StripDotProto(const std::string& proto_file);
      52             : std::string LabelForField(google::protobuf::FieldDescriptor* field);
      53             : std::string TypeName(google::protobuf::FieldDescriptor* field);
      54             : void GenerateMessage(const google::protobuf::Descriptor* message,
      55             :                      google::protobuf::io::Printer* printer);
      56             : void GenerateEnum(const google::protobuf::EnumDescriptor* en,
      57             :                   google::protobuf::io::Printer* printer);
      58             : void GenerateMessageAssignment(
      59             :     const std::string& prefix,
      60             :     const google::protobuf::Descriptor* message,
      61             :     google::protobuf::io::Printer* printer);
      62             : void GenerateEnumAssignment(
      63             :     const std::string& prefix,
      64             :     const google::protobuf::EnumDescriptor* en,
      65             :     google::protobuf::io::Printer* printer);
      66             : 
      67           0 : std::string IntToString(int32 value) {
      68           0 :   std::ostringstream os;
      69           0 :   os << value;
      70           0 :   return os.str();
      71             : }
      72             : 
      73           0 : std::string StripDotProto(const std::string& proto_file) {
      74           0 :   int lastindex = proto_file.find_last_of(".");
      75           0 :   return proto_file.substr(0, lastindex);
      76             : }
      77             : 
      78           0 : std::string LabelForField(const google::protobuf::FieldDescriptor* field) {
      79           0 :   switch (field->label()) {
      80           0 :     case FieldDescriptor::LABEL_OPTIONAL: return "optional";
      81           0 :     case FieldDescriptor::LABEL_REQUIRED: return "required";
      82           0 :     case FieldDescriptor::LABEL_REPEATED: return "repeated";
      83           0 :     default: assert(false); return "";
      84             :   }
      85             : }
      86             : 
      87           0 : std::string TypeName(const google::protobuf::FieldDescriptor* field) {
      88           0 :   switch (field->type()) {
      89           0 :     case FieldDescriptor::TYPE_INT32: return "int32";
      90           0 :     case FieldDescriptor::TYPE_INT64: return "int64";
      91           0 :     case FieldDescriptor::TYPE_UINT32: return "uint32";
      92           0 :     case FieldDescriptor::TYPE_UINT64: return "uint64";
      93           0 :     case FieldDescriptor::TYPE_SINT32: return "sint32";
      94           0 :     case FieldDescriptor::TYPE_SINT64: return "sint64";
      95           0 :     case FieldDescriptor::TYPE_FIXED32: return "fixed32";
      96           0 :     case FieldDescriptor::TYPE_FIXED64: return "fixed64";
      97           0 :     case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
      98           0 :     case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
      99           0 :     case FieldDescriptor::TYPE_DOUBLE: return "double";
     100           0 :     case FieldDescriptor::TYPE_FLOAT: return "float";
     101           0 :     case FieldDescriptor::TYPE_BOOL: return "bool";
     102           0 :     case FieldDescriptor::TYPE_ENUM: return "enum";
     103           0 :     case FieldDescriptor::TYPE_STRING: return "string";
     104           0 :     case FieldDescriptor::TYPE_BYTES: return "bytes";
     105           0 :     case FieldDescriptor::TYPE_MESSAGE: return "message";
     106           0 :     case FieldDescriptor::TYPE_GROUP: return "group";
     107           0 :     default: assert(false); return "";
     108             :   }
     109             : }
     110             : 
     111           0 : void GenerateField(const google::protobuf::FieldDescriptor* field,
     112             :                    google::protobuf::io::Printer* printer) {
     113             : 
     114           0 :   if (field->is_map()) {
     115             :     const FieldDescriptor* key_field =
     116           0 :         field->message_type()->FindFieldByNumber(1);
     117           0 :     const FieldDescriptor* value_field =
     118           0 :         field->message_type()->FindFieldByNumber(2);
     119             : 
     120             :     printer->Print(
     121             :       "map :$name$, :$key_type$, :$value_type$, $number$",
     122           0 :       "name", field->name(),
     123             :       "key_type", TypeName(key_field),
     124             :       "value_type", TypeName(value_field),
     125           0 :       "number", IntToString(field->number()));
     126             : 
     127           0 :     if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     128             :       printer->Print(
     129             :         ", \"$subtype$\"\n",
     130           0 :         "subtype", value_field->message_type()->full_name());
     131           0 :     } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
     132             :       printer->Print(
     133             :         ", \"$subtype$\"\n",
     134           0 :         "subtype", value_field->enum_type()->full_name());
     135             :     } else {
     136           0 :       printer->Print("\n");
     137             :     }
     138             :   } else {
     139             : 
     140             :     printer->Print(
     141             :       "$label$ :$name$, ",
     142             :       "label", LabelForField(field),
     143           0 :       "name", field->name());
     144             :     printer->Print(
     145             :       ":$type$, $number$",
     146             :       "type", TypeName(field),
     147           0 :       "number", IntToString(field->number()));
     148             : 
     149           0 :     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     150             :       printer->Print(
     151             :         ", \"$subtype$\"\n",
     152           0 :        "subtype", field->message_type()->full_name());
     153           0 :     } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
     154             :       printer->Print(
     155             :         ", \"$subtype$\"\n",
     156           0 :         "subtype", field->enum_type()->full_name());
     157             :     } else {
     158           0 :       printer->Print("\n");
     159             :     }
     160             :   }
     161           0 : }
     162             : 
     163           0 : void GenerateOneof(const google::protobuf::OneofDescriptor* oneof,
     164             :                    google::protobuf::io::Printer* printer) {
     165             :   printer->Print(
     166             :       "oneof :$name$ do\n",
     167           0 :       "name", oneof->name());
     168           0 :   printer->Indent();
     169             : 
     170           0 :   for (int i = 0; i < oneof->field_count(); i++) {
     171           0 :     const FieldDescriptor* field = oneof->field(i);
     172           0 :     GenerateField(field, printer);
     173             :   }
     174             : 
     175           0 :   printer->Outdent();
     176           0 :   printer->Print("end\n");
     177           0 : }
     178             : 
     179           0 : void GenerateMessage(const google::protobuf::Descriptor* message,
     180             :                      google::protobuf::io::Printer* printer) {
     181             : 
     182             :   // Don't generate MapEntry messages -- we use the Ruby extension's native
     183             :   // support for map fields instead.
     184           0 :   if (message->options().map_entry()) {
     185           0 :     return;
     186             :   }
     187             : 
     188             :   printer->Print(
     189             :     "add_message \"$name$\" do\n",
     190           0 :     "name", message->full_name());
     191           0 :   printer->Indent();
     192             : 
     193           0 :   for (int i = 0; i < message->field_count(); i++) {
     194           0 :     const FieldDescriptor* field = message->field(i);
     195           0 :     if (!field->containing_oneof()) {
     196           0 :       GenerateField(field, printer);
     197             :     }
     198             :   }
     199             : 
     200           0 :   for (int i = 0; i < message->oneof_decl_count(); i++) {
     201           0 :     const OneofDescriptor* oneof = message->oneof_decl(i);
     202           0 :     GenerateOneof(oneof, printer);
     203             :   }
     204             : 
     205           0 :   printer->Outdent();
     206           0 :   printer->Print("end\n");
     207             : 
     208           0 :   for (int i = 0; i < message->nested_type_count(); i++) {
     209           0 :     GenerateMessage(message->nested_type(i), printer);
     210             :   }
     211           0 :   for (int i = 0; i < message->enum_type_count(); i++) {
     212           0 :     GenerateEnum(message->enum_type(i), printer);
     213             :   }
     214             : }
     215             : 
     216           0 : void GenerateEnum(const google::protobuf::EnumDescriptor* en,
     217             :                   google::protobuf::io::Printer* printer) {
     218             :   printer->Print(
     219             :     "add_enum \"$name$\" do\n",
     220           0 :     "name", en->full_name());
     221           0 :   printer->Indent();
     222             : 
     223           0 :   for (int i = 0; i < en->value_count(); i++) {
     224           0 :     const EnumValueDescriptor* value = en->value(i);
     225             :     printer->Print(
     226             :       "value :$name$, $number$\n",
     227           0 :       "name", value->name(),
     228           0 :       "number", IntToString(value->number()));
     229             :   }
     230             : 
     231           0 :   printer->Outdent();
     232             :   printer->Print(
     233           0 :     "end\n");
     234           0 : }
     235             : 
     236             : // Module names, class names, and enum value names need to be Ruby constants,
     237             : // which must start with a capital letter.
     238           0 : std::string RubifyConstant(const std::string& name) {
     239           0 :   std::string ret = name;
     240           0 :   if (!ret.empty()) {
     241           0 :     if (ret[0] >= 'a' && ret[0] <= 'z') {
     242             :       // If it starts with a lowercase letter, capitalize it.
     243           0 :       ret[0] = ret[0] - 'a' + 'A';
     244           0 :     } else if (ret[0] < 'A' || ret[0] > 'Z') {
     245             :       // Otherwise (e.g. if it begins with an underscore), we need to come up
     246             :       // with some prefix that starts with a capital letter. We could be smarter
     247             :       // here, e.g. try to strip leading underscores, but this may cause other
     248             :       // problems if the user really intended the name. So let's just prepend a
     249             :       // well-known suffix.
     250           0 :       ret = "PB_" + ret;
     251             :     }
     252             :   }
     253           0 :   return ret;
     254             : }
     255             : 
     256           0 : void GenerateMessageAssignment(
     257             :     const std::string& prefix,
     258           0 :     const google::protobuf::Descriptor* message,
     259             :     google::protobuf::io::Printer* printer) {
     260             : 
     261             :   // Don't generate MapEntry messages -- we use the Ruby extension's native
     262             :   // support for map fields instead.
     263           0 :   if (message->options().map_entry()) {
     264           0 :     return;
     265             :   }
     266             : 
     267             :   printer->Print(
     268             :     "$prefix$$name$ = ",
     269             :     "prefix", prefix,
     270           0 :     "name", RubifyConstant(message->name()));
     271             :   printer->Print(
     272             :     "Google::Protobuf::DescriptorPool.generated_pool."
     273             :     "lookup(\"$full_name$\").msgclass\n",
     274           0 :     "full_name", message->full_name());
     275             : 
     276           0 :   std::string nested_prefix = prefix + message->name() + "::";
     277           0 :   for (int i = 0; i < message->nested_type_count(); i++) {
     278           0 :     GenerateMessageAssignment(nested_prefix, message->nested_type(i), printer);
     279             :   }
     280           0 :   for (int i = 0; i < message->enum_type_count(); i++) {
     281           0 :     GenerateEnumAssignment(nested_prefix, message->enum_type(i), printer);
     282             :   }
     283             : }
     284             : 
     285           0 : void GenerateEnumAssignment(
     286             :     const std::string& prefix,
     287           0 :     const google::protobuf::EnumDescriptor* en,
     288             :     google::protobuf::io::Printer* printer) {
     289             :   printer->Print(
     290             :     "$prefix$$name$ = ",
     291             :     "prefix", prefix,
     292           0 :     "name", RubifyConstant(en->name()));
     293             :   printer->Print(
     294             :     "Google::Protobuf::DescriptorPool.generated_pool."
     295             :     "lookup(\"$full_name$\").enummodule\n",
     296           0 :     "full_name", en->full_name());
     297           0 : }
     298             : 
     299           0 : int GeneratePackageModules(
     300             :     std::string package_name,
     301             :     google::protobuf::io::Printer* printer) {
     302           0 :   int levels = 0;
     303           0 :   while (!package_name.empty()) {
     304           0 :     size_t dot_index = package_name.find(".");
     305             :     string component;
     306           0 :     if (dot_index == string::npos) {
     307             :       component = package_name;
     308             :       package_name = "";
     309             :     } else {
     310           0 :       component = package_name.substr(0, dot_index);
     311           0 :       package_name = package_name.substr(dot_index + 1);
     312             :     }
     313           0 :     component = RubifyConstant(component);
     314             :     printer->Print(
     315             :       "module $name$\n",
     316           0 :       "name", component);
     317           0 :     printer->Indent();
     318           0 :     levels++;
     319             :   }
     320           0 :   return levels;
     321             : }
     322             : 
     323           0 : void EndPackageModules(
     324             :     int levels,
     325             :     google::protobuf::io::Printer* printer) {
     326           0 :   while (levels > 0) {
     327           0 :     levels--;
     328           0 :     printer->Outdent();
     329             :     printer->Print(
     330           0 :       "end\n");
     331             :   }
     332           0 : }
     333             : 
     334           0 : void GenerateFile(const google::protobuf::FileDescriptor* file,
     335             :                   google::protobuf::io::Printer* printer) {
     336             :   printer->Print(
     337             :     "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     338             :     "# source: $filename$\n"
     339             :     "\n",
     340           0 :     "filename", file->name());
     341             : 
     342             :   printer->Print(
     343           0 :     "require 'google/protobuf'\n\n");
     344             : 
     345           0 :   for (int i = 0; i < file->dependency_count(); i++) {
     346           0 :     const std::string& name = file->dependency(i)->name();
     347             :     printer->Print(
     348           0 :       "require '$name$'\n", "name", StripDotProto(name));
     349             :   }
     350             : 
     351             :   printer->Print(
     352           0 :     "Google::Protobuf::DescriptorPool.generated_pool.build do\n");
     353           0 :   printer->Indent();
     354           0 :   for (int i = 0; i < file->message_type_count(); i++) {
     355           0 :     GenerateMessage(file->message_type(i), printer);
     356             :   }
     357           0 :   for (int i = 0; i < file->enum_type_count(); i++) {
     358           0 :     GenerateEnum(file->enum_type(i), printer);
     359             :   }
     360           0 :   printer->Outdent();
     361             :   printer->Print(
     362           0 :     "end\n\n");
     363             : 
     364           0 :   int levels = GeneratePackageModules(file->package(), printer);
     365           0 :   for (int i = 0; i < file->message_type_count(); i++) {
     366           0 :     GenerateMessageAssignment("", file->message_type(i), printer);
     367             :   }
     368           0 :   for (int i = 0; i < file->enum_type_count(); i++) {
     369           0 :     GenerateEnumAssignment("", file->enum_type(i), printer);
     370             :   }
     371           0 :   EndPackageModules(levels, printer);
     372           0 : }
     373             : 
     374           0 : bool Generator::Generate(
     375           0 :     const FileDescriptor* file,
     376             :     const string& parameter,
     377             :     GeneratorContext* generator_context,
     378             :     string* error) const {
     379             : 
     380           0 :   if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
     381             :     *error =
     382             :         "Can only generate Ruby code for proto3 .proto files.\n"
     383             :         "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
     384             :     return false;
     385             :   }
     386             : 
     387             :   std::string filename =
     388           0 :       StripDotProto(file->name()) + ".rb";
     389             :   scoped_ptr<io::ZeroCopyOutputStream> output(
     390           0 :       generator_context->Open(filename));
     391           0 :   io::Printer printer(output.get(), '$');
     392             : 
     393           0 :   GenerateFile(file, &printer);
     394             : 
     395             :   return true;
     396             : }
     397             : 
     398             : }  // namespace ruby
     399             : }  // namespace compiler
     400             : }  // namespace protobuf
     401             : }  // namespace google

Generated by: LCOV version 1.10