Home | History | Annotate | Download | only in javamicro
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      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 // Author: kenton (at) google.com (Kenton Varda)
     32 //  Based on original Protocol Buffers design by
     33 //  Sanjay Ghemawat, Jeff Dean, and others.
     34 
     35 #include <algorithm>
     36 #include <google/protobuf/stubs/hash.h>
     37 #include <google/protobuf/compiler/javamicro/javamicro_message.h>
     38 #include <google/protobuf/compiler/javamicro/javamicro_enum.h>
     39 #include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
     40 #include <google/protobuf/stubs/strutil.h>
     41 #include <google/protobuf/io/printer.h>
     42 #include <google/protobuf/io/coded_stream.h>
     43 #include <google/protobuf/wire_format.h>
     44 #include <google/protobuf/descriptor.pb.h>
     45 
     46 namespace google {
     47 namespace protobuf {
     48 namespace compiler {
     49 namespace javamicro {
     50 
     51 using internal::WireFormat;
     52 using internal::WireFormatLite;
     53 
     54 namespace {
     55 
     56 void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
     57   // Print the field's proto-syntax definition as a comment.  We don't want to
     58   // print group bodies so we cut off after the first line.
     59   string def = field->DebugString();
     60   printer->Print("// $def$\n",
     61     "def", def.substr(0, def.find_first_of('\n')));
     62 }
     63 
     64 struct FieldOrderingByNumber {
     65   inline bool operator()(const FieldDescriptor* a,
     66                          const FieldDescriptor* b) const {
     67     return a->number() < b->number();
     68   }
     69 };
     70 
     71 // Sort the fields of the given Descriptor by number into a new[]'d array
     72 // and return it.
     73 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
     74   const FieldDescriptor** fields =
     75     new const FieldDescriptor*[descriptor->field_count()];
     76   for (int i = 0; i < descriptor->field_count(); i++) {
     77     fields[i] = descriptor->field(i);
     78   }
     79   sort(fields, fields + descriptor->field_count(),
     80        FieldOrderingByNumber());
     81   return fields;
     82 }
     83 
     84 // Get an identifier that uniquely identifies this type within the file.
     85 // This is used to declare static variables related to this type at the
     86 // outermost file scope.
     87 string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
     88   return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
     89 }
     90 
     91 // Returns true if the message type has any required fields.  If it doesn't,
     92 // we can optimize out calls to its isInitialized() method.
     93 //
     94 // already_seen is used to avoid checking the same type multiple times
     95 // (and also to protect against recursion).
     96 static bool HasRequiredFields(
     97     const Descriptor* type,
     98     hash_set<const Descriptor*>* already_seen) {
     99   if (already_seen->count(type) > 0) {
    100     // The type is already in cache.  This means that either:
    101     // a. The type has no required fields.
    102     // b. We are in the midst of checking if the type has required fields,
    103     //    somewhere up the stack.  In this case, we know that if the type
    104     //    has any required fields, they'll be found when we return to it,
    105     //    and the whole call to HasRequiredFields() will return true.
    106     //    Therefore, we don't have to check if this type has required fields
    107     //    here.
    108     return false;
    109   }
    110   already_seen->insert(type);
    111 
    112   // If the type has extensions, an extension with message type could contain
    113   // required fields, so we have to be conservative and assume such an
    114   // extension exists.
    115   if (type->extension_range_count() > 0) return true;
    116 
    117   for (int i = 0; i < type->field_count(); i++) {
    118     const FieldDescriptor* field = type->field(i);
    119     if (field->is_required()) {
    120       return true;
    121     }
    122     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
    123       if (HasRequiredFields(field->message_type(), already_seen)) {
    124         return true;
    125       }
    126     }
    127   }
    128 
    129   return false;
    130 }
    131 
    132 static bool HasRequiredFields(const Descriptor* type) {
    133   hash_set<const Descriptor*> already_seen;
    134   return HasRequiredFields(type, &already_seen);
    135 }
    136 
    137 }  // namespace
    138 
    139 // ===================================================================
    140 
    141 MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
    142   : params_(params),
    143     descriptor_(descriptor),
    144     field_generators_(descriptor, params) {
    145 }
    146 
    147 MessageGenerator::~MessageGenerator() {}
    148 
    149 void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
    150   // Generate static members for all nested types.
    151   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
    152     // TODO(kenton):  Reuse MessageGenerator objects?
    153     MessageGenerator(descriptor_->nested_type(i), params_)
    154       .GenerateStaticVariables(printer);
    155   }
    156 }
    157 
    158 void MessageGenerator::GenerateStaticVariableInitializers(
    159     io::Printer* printer) {
    160   // Generate static member initializers for all nested types.
    161   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
    162     // TODO(kenton):  Reuse MessageGenerator objects?
    163     MessageGenerator(descriptor_->nested_type(i), params_)
    164       .GenerateStaticVariableInitializers(printer);
    165   }
    166 
    167   if (descriptor_->extension_count() != 0) {
    168     GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
    169   }
    170 }
    171 
    172 void MessageGenerator::Generate(io::Printer* printer) {
    173   bool is_own_file =
    174     params_.java_multiple_files() || ((descriptor_->containing_type() == NULL)
    175         && !params_.has_java_outer_classname(descriptor_->file()->name()));
    176 
    177 #if 0
    178   GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
    179   GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
    180   GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
    181   GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
    182 #endif
    183 
    184   if ((descriptor_->extension_count() != 0)
    185       || (descriptor_->extension_range_count() != 0)) {
    186     GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
    187   }
    188 
    189   // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
    190   // the inner or outer class.  This causes Java warnings, but is not fatal, so we suppress those
    191   // warnings here in the class declaration.
    192   printer->Print(
    193     "@SuppressWarnings(\"hiding\")\n"
    194     "public $modifiers$ final class $classname$ extends\n"
    195     "    com.google.protobuf.micro.MessageMicro {\n",
    196     "modifiers", is_own_file ? "" : "static",
    197     "classname", descriptor_->name());
    198   printer->Indent();
    199   printer->Print(
    200     "public $classname$() {}\n"
    201     "\n",
    202     "classname", descriptor_->name());
    203 
    204   // Nested types and extensions
    205   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
    206     EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
    207   }
    208 
    209   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
    210     MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
    211   }
    212 
    213   // Fields
    214   for (int i = 0; i < descriptor_->field_count(); i++) {
    215     PrintFieldComment(printer, descriptor_->field(i));
    216     printer->Print("public static final int $constant_name$ = $number$;\n",
    217       "constant_name", FieldConstantName(descriptor_->field(i)),
    218       "number", SimpleItoa(descriptor_->field(i)->number()));
    219     field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
    220     printer->Print("\n");
    221   }
    222 
    223   GenerateClear(printer);
    224   GenerateIsInitialized(printer);
    225   GenerateMessageSerializationMethods(printer);
    226   GenerateMergeFromMethods(printer);
    227   GenerateParseFromMethods(printer);
    228 
    229   printer->Outdent();
    230   printer->Print("}\n\n");
    231 }
    232 
    233 // ===================================================================
    234 
    235 void MessageGenerator::
    236 GenerateMessageSerializationMethods(io::Printer* printer) {
    237   scoped_array<const FieldDescriptor*> sorted_fields(
    238     SortFieldsByNumber(descriptor_));
    239 
    240   if (descriptor_->extension_range_count() != 0) {
    241     GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
    242   }
    243 
    244   // writeTo only throws an exception if it contains one or more fields to write
    245   if (descriptor_->field_count() > 0) {
    246     printer->Print(
    247       "@Override\n"
    248       "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n"
    249       "                    throws java.io.IOException {\n");
    250   } else {
    251     printer->Print(
    252       "@Override\n"
    253       "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output) {\n");
    254   }
    255   printer->Indent();
    256 
    257   // Output the fields in sorted order
    258   for (int i = 0; i < descriptor_->field_count(); i++) {
    259       GenerateSerializeOneField(printer, sorted_fields[i]);
    260   }
    261 
    262   printer->Outdent();
    263   printer->Print(
    264     "}\n"
    265     "\n"
    266     "private int cachedSize = -1;\n"
    267     "@Override\n"
    268     "public int getCachedSize() {\n"
    269     "  if (cachedSize < 0) {\n"
    270     "    // getSerializedSize sets cachedSize\n"
    271     "    getSerializedSize();\n"
    272     "  }\n"
    273     "  return cachedSize;\n"
    274     "}\n"
    275     "\n"
    276     "@Override\n"
    277     "public int getSerializedSize() {\n"
    278     "  int size = 0;\n");
    279   printer->Indent();
    280 
    281   for (int i = 0; i < descriptor_->field_count(); i++) {
    282     field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
    283   }
    284 
    285   printer->Outdent();
    286   printer->Print(
    287     "  cachedSize = size;\n"
    288     "  return size;\n"
    289     "}\n"
    290     "\n");
    291 }
    292 
    293 void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
    294   scoped_array<const FieldDescriptor*> sorted_fields(
    295     SortFieldsByNumber(descriptor_));
    296 
    297   if (params_.java_use_vector()) {
    298     printer->Print(
    299       "@Override\n"
    300       "public com.google.protobuf.micro.MessageMicro mergeFrom(\n"
    301       "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
    302       "    throws java.io.IOException {\n",
    303       "classname", descriptor_->name());
    304   } else {
    305     printer->Print(
    306       "@Override\n"
    307       "public $classname$ mergeFrom(\n"
    308       "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
    309       "    throws java.io.IOException {\n",
    310       "classname", descriptor_->name());
    311   }
    312   printer->Indent();
    313 
    314   printer->Print(
    315     "while (true) {\n");
    316   printer->Indent();
    317 
    318   printer->Print(
    319     "int tag = input.readTag();\n"
    320     "switch (tag) {\n");
    321   printer->Indent();
    322 
    323   printer->Print(
    324     "case 0:\n"          // zero signals EOF / limit reached
    325     "  return this;\n"
    326     "default: {\n"
    327     "  if (!parseUnknownField(input, tag)) {\n"
    328     "    return this;\n"   // it's an endgroup tag
    329     "  }\n"
    330     "  break;\n"
    331     "}\n");
    332 
    333   for (int i = 0; i < descriptor_->field_count(); i++) {
    334     const FieldDescriptor* field = sorted_fields[i];
    335     uint32 tag = WireFormatLite::MakeTag(field->number(),
    336       WireFormat::WireTypeForField(field));
    337 
    338     printer->Print(
    339       "case $tag$: {\n",
    340       "tag", SimpleItoa(tag));
    341     printer->Indent();
    342 
    343     field_generators_.get(field).GenerateParsingCode(printer);
    344 
    345     printer->Outdent();
    346     printer->Print(
    347       "  break;\n"
    348       "}\n");
    349   }
    350 
    351   printer->Outdent();
    352   printer->Outdent();
    353   printer->Outdent();
    354   printer->Print(
    355     "    }\n"     // switch (tag)
    356     "  }\n"       // while (true)
    357     "}\n"
    358     "\n");
    359 }
    360 
    361 void MessageGenerator::
    362 GenerateParseFromMethods(io::Printer* printer) {
    363   bool is_own_file =
    364     descriptor_->containing_type() == NULL;
    365 
    366   // Note:  These are separate from GenerateMessageSerializationMethods()
    367   //   because they need to be generated even for messages that are optimized
    368   //   for code size.
    369   printer->Print(
    370     "public $static$ $classname$ parseFrom(byte[] data)\n"
    371     "    throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n"
    372     "  return ($classname$) (new $classname$().mergeFrom(data));\n"
    373     "}\n"
    374     "\n"
    375     "public $static$ $classname$ parseFrom(\n"
    376     "        com.google.protobuf.micro.CodedInputStreamMicro input)\n"
    377     "    throws java.io.IOException {\n"
    378     "  return new $classname$().mergeFrom(input);\n"
    379     "}\n"
    380     "\n",
    381     "static", (is_own_file ? "static" : ""),
    382     "classname", descriptor_->name());
    383 }
    384 
    385 void MessageGenerator::GenerateSerializeOneField(
    386     io::Printer* printer, const FieldDescriptor* field) {
    387   field_generators_.get(field).GenerateSerializationCode(printer);
    388 }
    389 
    390 void MessageGenerator::GenerateClear(io::Printer* printer) {
    391   printer->Print(
    392     "public final $classname$ clear() {\n",
    393     "classname", descriptor_->name());
    394   printer->Indent();
    395 
    396   // Call clear for all of the fields.
    397   for (int i = 0; i < descriptor_->field_count(); i++) {
    398     const FieldDescriptor* field = descriptor_->field(i);
    399 
    400     printer->Print(
    401       "clear$name$();\n",
    402       "name", UnderscoresToCapitalizedCamelCase(field));
    403   }
    404 
    405   printer->Outdent();
    406   printer->Print(
    407     "  cachedSize = -1;\n"
    408     "  return this;\n"
    409     "}\n"
    410     "\n");
    411 }
    412 
    413 
    414 void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
    415   printer->Print(
    416     "public final boolean isInitialized() {\n");
    417   printer->Indent();
    418 
    419   // Check that all required fields in this message are set.
    420   // TODO(kenton):  We can optimize this when we switch to putting all the
    421   //   "has" fields into a single bitfield.
    422   for (int i = 0; i < descriptor_->field_count(); i++) {
    423     const FieldDescriptor* field = descriptor_->field(i);
    424 
    425     if (field->is_required()) {
    426       printer->Print(
    427         "if (!has$name$) return false;\n",
    428         "name", UnderscoresToCapitalizedCamelCase(field));
    429     }
    430   }
    431 
    432   // Now check that all embedded messages are initialized.
    433   for (int i = 0; i < descriptor_->field_count(); i++) {
    434     const FieldDescriptor* field = descriptor_->field(i);
    435     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
    436         HasRequiredFields(field->message_type())) {
    437       switch (field->label()) {
    438         case FieldDescriptor::LABEL_REQUIRED:
    439           printer->Print(
    440             "if (!get$name$().isInitialized()) return false;\n",
    441             "type", ClassName(params_, field->message_type()),
    442             "name", UnderscoresToCapitalizedCamelCase(field));
    443           break;
    444         case FieldDescriptor::LABEL_OPTIONAL:
    445           printer->Print(
    446             "if (has$name$()) {\n"
    447             "  if (!get$name$().isInitialized()) return false;\n"
    448             "}\n",
    449             "type", ClassName(params_, field->message_type()),
    450             "name", UnderscoresToCapitalizedCamelCase(field));
    451           break;
    452         case FieldDescriptor::LABEL_REPEATED:
    453           if (params_.java_use_vector()) {
    454             printer->Print(
    455               "for (int i = 0; i < get$name$List().size(); i++) {\n"
    456               "  if (get$name$(i).isInitialized()) return false;\n"
    457               "}\n",
    458               "type", ClassName(params_, field->message_type()),
    459               "name", UnderscoresToCapitalizedCamelCase(field));
    460           } else {
    461             printer->Print(
    462               "for ($type$ element : get$name$List()) {\n"
    463               "  if (!element.isInitialized()) return false;\n"
    464               "}\n",
    465               "type", ClassName(params_, field->message_type()),
    466               "name", UnderscoresToCapitalizedCamelCase(field));
    467           }
    468           break;
    469       }
    470     }
    471   }
    472 
    473   if (descriptor_->extension_range_count() > 0) {
    474     printer->Print(
    475       "if (!extensionsAreInitialized()) return false;\n");
    476   }
    477 
    478   printer->Outdent();
    479   printer->Print(
    480     "  return true;\n"
    481     "}\n"
    482     "\n");
    483 }
    484 
    485 // ===================================================================
    486 
    487 }  // namespace javamicro
    488 }  // namespace compiler
    489 }  // namespace protobuf
    490 }  // namespace google
    491