Home | History | Annotate | Download | only in cpp
      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 <google/protobuf/compiler/cpp/cpp_extension.h>
     36 #include <map>
     37 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
     38 #include <google/protobuf/stubs/strutil.h>
     39 #include <google/protobuf/io/printer.h>
     40 #include <google/protobuf/descriptor.pb.h>
     41 
     42 namespace google {
     43 namespace protobuf {
     44 namespace compiler {
     45 namespace cpp {
     46 
     47 namespace {
     48 
     49 // Returns the fully-qualified class name of the message that this field
     50 // extends. This function is used in the Google-internal code to handle some
     51 // legacy cases.
     52 string ExtendeeClassName(const FieldDescriptor* descriptor) {
     53   const Descriptor* extendee = descriptor->containing_type();
     54   return ClassName(extendee, true);
     55 }
     56 
     57 }  // anonymous namespace
     58 
     59 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
     60                                        const string& dllexport_decl)
     61   : descriptor_(descriptor),
     62     dllexport_decl_(dllexport_decl) {
     63   // Construct type_traits_.
     64   if (descriptor_->is_repeated()) {
     65     type_traits_ = "Repeated";
     66   }
     67 
     68   switch (descriptor_->cpp_type()) {
     69     case FieldDescriptor::CPPTYPE_ENUM:
     70       type_traits_.append("EnumTypeTraits< ");
     71       type_traits_.append(ClassName(descriptor_->enum_type(), true));
     72       type_traits_.append(", ");
     73       type_traits_.append(ClassName(descriptor_->enum_type(), true));
     74       type_traits_.append("_IsValid>");
     75       break;
     76     case FieldDescriptor::CPPTYPE_STRING:
     77       type_traits_.append("StringTypeTraits");
     78       break;
     79     case FieldDescriptor::CPPTYPE_MESSAGE:
     80       type_traits_.append("MessageTypeTraits< ");
     81       type_traits_.append(ClassName(descriptor_->message_type(), true));
     82       type_traits_.append(" >");
     83       break;
     84     default:
     85       type_traits_.append("PrimitiveTypeTraits< ");
     86       type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type()));
     87       type_traits_.append(" >");
     88       break;
     89   }
     90 }
     91 
     92 ExtensionGenerator::~ExtensionGenerator() {}
     93 
     94 void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
     95   map<string, string> vars;
     96   vars["extendee"     ] = ExtendeeClassName(descriptor_);
     97   vars["number"       ] = SimpleItoa(descriptor_->number());
     98   vars["type_traits"  ] = type_traits_;
     99   vars["name"         ] = descriptor_->name();
    100   vars["field_type"   ] = SimpleItoa(static_cast<int>(descriptor_->type()));
    101   vars["packed"       ] = descriptor_->options().packed() ? "true" : "false";
    102   vars["constant_name"] = FieldConstantName(descriptor_);
    103 
    104   // If this is a class member, it needs to be declared "static".  Otherwise,
    105   // it needs to be "extern".  In the latter case, it also needs the DLL
    106   // export/import specifier.
    107   if (descriptor_->extension_scope() == NULL) {
    108     vars["qualifier"] = "extern";
    109     if (!dllexport_decl_.empty()) {
    110       vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
    111     }
    112   } else {
    113     vars["qualifier"] = "static";
    114   }
    115 
    116   printer->Print(vars,
    117     "static const int $constant_name$ = $number$;\n"
    118     "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
    119     "    ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
    120     "  $name$;\n"
    121     );
    122 
    123 }
    124 
    125 void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
    126   // If this is a class member, it needs to be declared in its class scope.
    127   string scope = (descriptor_->extension_scope() == NULL) ? "" :
    128     ClassName(descriptor_->extension_scope(), false) + "::";
    129   string name = scope + descriptor_->name();
    130 
    131   map<string, string> vars;
    132   vars["extendee"     ] = ExtendeeClassName(descriptor_);
    133   vars["type_traits"  ] = type_traits_;
    134   vars["name"         ] = name;
    135   vars["constant_name"] = FieldConstantName(descriptor_);
    136   vars["default"      ] = DefaultValue(descriptor_);
    137   vars["field_type"   ] = SimpleItoa(static_cast<int>(descriptor_->type()));
    138   vars["packed"       ] = descriptor_->options().packed() ? "true" : "false";
    139   vars["scope"        ] = scope;
    140 
    141   if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
    142     // We need to declare a global string which will contain the default value.
    143     // We cannot declare it at class scope because that would require exposing
    144     // it in the header which would be annoying for other reasons.  So we
    145     // replace :: with _ in the name and declare it as a global.
    146     string global_name = StringReplace(name, "::", "_", true);
    147     vars["global_name"] = global_name;
    148     printer->Print(vars,
    149       "const ::std::string $global_name$_default($default$);\n");
    150 
    151     // Update the default to refer to the string global.
    152     vars["default"] = global_name + "_default";
    153   }
    154 
    155   // Likewise, class members need to declare the field constant variable.
    156   if (descriptor_->extension_scope() != NULL) {
    157     printer->Print(vars,
    158       "#ifndef _MSC_VER\n"
    159       "const int $scope$$constant_name$;\n"
    160       "#endif\n");
    161   }
    162 
    163   printer->Print(vars,
    164     "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
    165     "    ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
    166     "  $name$($constant_name$, $default$);\n");
    167 }
    168 
    169 void ExtensionGenerator::GenerateRegistration(io::Printer* printer) {
    170   map<string, string> vars;
    171   vars["extendee"   ] = ExtendeeClassName(descriptor_);
    172   vars["number"     ] = SimpleItoa(descriptor_->number());
    173   vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
    174   vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false";
    175   vars["is_packed"  ] = (descriptor_->is_repeated() &&
    176                          descriptor_->options().packed())
    177                         ? "true" : "false";
    178 
    179   switch (descriptor_->cpp_type()) {
    180     case FieldDescriptor::CPPTYPE_ENUM:
    181       printer->Print(vars,
    182         "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n"
    183         "  &$extendee$::default_instance(),\n"
    184         "  $number$, $field_type$, $is_repeated$, $is_packed$,\n");
    185       printer->Print(
    186         "  &$type$_IsValid);\n",
    187         "type", ClassName(descriptor_->enum_type(), true));
    188       break;
    189     case FieldDescriptor::CPPTYPE_MESSAGE:
    190       printer->Print(vars,
    191         "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n"
    192         "  &$extendee$::default_instance(),\n"
    193         "  $number$, $field_type$, $is_repeated$, $is_packed$,\n");
    194       printer->Print(
    195         "  &$type$::default_instance());\n",
    196         "type", ClassName(descriptor_->message_type(), true));
    197       break;
    198     default:
    199       printer->Print(vars,
    200         "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n"
    201         "  &$extendee$::default_instance(),\n"
    202         "  $number$, $field_type$, $is_repeated$, $is_packed$);\n");
    203       break;
    204   }
    205 }
    206 
    207 }  // namespace cpp
    208 }  // namespace compiler
    209 }  // namespace protobuf
    210 }  // namespace google
    211