LCOV - code coverage report
Current view: top level - third_party/protobuf/src/google/protobuf/compiler/cpp - cpp_enum.cc (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 98 103 95.1 %
Date: 2015-10-10 Functions: 7 8 87.5 %

          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             : // Author: kenton@google.com (Kenton Varda)
      32             : //  Based on original Protocol Buffers design by
      33             : //  Sanjay Ghemawat, Jeff Dean, and others.
      34             : 
      35             : #include <map>
      36             : 
      37             : #include <google/protobuf/compiler/cpp/cpp_enum.h>
      38             : #include <google/protobuf/compiler/cpp/cpp_helpers.h>
      39             : #include <google/protobuf/io/printer.h>
      40             : #include <google/protobuf/stubs/strutil.h>
      41             : 
      42             : namespace google {
      43             : namespace protobuf {
      44             : namespace compiler {
      45             : namespace cpp {
      46             : 
      47             : namespace {
      48             : // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
      49             : // is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
      50             : // generation of the GOOGLE_ARRAYSIZE constant.
      51         237 : bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
      52          47 :   int32 max_value = descriptor->value(0)->number();
      53         380 :   for (int i = 0; i < descriptor->value_count(); i++) {
      54         286 :     if (descriptor->value(i)->number() > max_value) {
      55          86 :       max_value = descriptor->value(i)->number();
      56             :     }
      57             :   }
      58          47 :   return max_value != ::google::protobuf::kint32max;
      59             : }
      60             : }  // namespace
      61             : 
      62          47 : EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
      63             :                              const Options& options)
      64             :   : descriptor_(descriptor),
      65             :     classname_(ClassName(descriptor, false)),
      66             :     options_(options),
      67          94 :     generate_array_size_(ShouldGenerateArraySize(descriptor)) {
      68          47 : }
      69             : 
      70         141 : EnumGenerator::~EnumGenerator() {}
      71             : 
      72           0 : void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) {
      73           0 :   if (!options_.proto_h) {
      74           0 :     return;
      75             :   }
      76           0 :   enum_names->insert(classname_);
      77             : }
      78             : 
      79          47 : void EnumGenerator::GenerateDefinition(io::Printer* printer) {
      80             :   map<string, string> vars;
      81          94 :   vars["classname"] = classname_;
      82         997 :   vars["short_name"] = descriptor_->name();
      83         141 :   vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
      84             : 
      85          47 :   printer->Print(vars, "enum $enumbase$ {\n");
      86          47 :   printer->Indent();
      87             : 
      88         237 :   const EnumValueDescriptor* min_value = descriptor_->value(0);
      89         190 :   const EnumValueDescriptor* max_value = descriptor_->value(0);
      90             : 
      91         380 :   for (int i = 0; i < descriptor_->value_count(); i++) {
      92         572 :     vars["name"] = EnumValueName(descriptor_->value(i));
      93             :     // In C++, an value of -2147483648 gets interpreted as the negative of
      94             :     // 2147483648, and since 2147483648 can't fit in an integer, this produces a
      95             :     // compiler warning.  This works around that issue.
      96         715 :     vars["number"] = Int32ToString(descriptor_->value(i)->number());
      97         665 :     vars["prefix"] = (descriptor_->containing_type() == NULL) ?
      98          50 :       "" : classname_ + "_";
      99             : 
     100         143 :     if (i > 0) printer->Print(",\n");
     101         143 :     printer->Print(vars, "$prefix$$name$ = $number$");
     102             : 
     103         572 :     if (descriptor_->value(i)->number() < min_value->number()) {
     104           6 :       min_value = descriptor_->value(i);
     105             :     }
     106         286 :     if (descriptor_->value(i)->number() > max_value->number()) {
     107          86 :       max_value = descriptor_->value(i);
     108             :     }
     109             :   }
     110             : 
     111          94 :   if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
     112             :     // For new enum semantics: generate min and max sentinel values equal to
     113             :     // INT32_MIN and INT32_MAX
     114          19 :     if (descriptor_->value_count() > 0) printer->Print(",\n");
     115             :     printer->Print(vars,
     116             :         "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n"
     117          19 :         "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max");
     118             :   }
     119             : 
     120          47 :   printer->Outdent();
     121          47 :   printer->Print("\n};\n");
     122             : 
     123         141 :   vars["min_name"] = EnumValueName(min_value);
     124         141 :   vars["max_name"] = EnumValueName(max_value);
     125             : 
     126          94 :   if (options_.dllexport_decl.empty()) {
     127          94 :     vars["dllexport"] = "";
     128             :   } else {
     129           0 :     vars["dllexport"] = options_.dllexport_decl + " ";
     130             :   }
     131             : 
     132             :   printer->Print(vars,
     133             :     "$dllexport$bool $classname$_IsValid(int value);\n"
     134             :     "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
     135          47 :     "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n");
     136             : 
     137          47 :   if (generate_array_size_) {
     138             :     printer->Print(vars,
     139             :       "const int $prefix$$short_name$_ARRAYSIZE = "
     140          46 :       "$prefix$$short_name$_MAX + 1;\n\n");
     141             :   }
     142             : 
     143         141 :   if (HasDescriptorMethods(descriptor_->file())) {
     144             :     printer->Print(vars,
     145          41 :       "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
     146             :     // The _Name and _Parse methods
     147             :     printer->Print(vars,
     148             :       "inline const ::std::string& $classname$_Name($classname$ value) {\n"
     149             :       "  return ::google::protobuf::internal::NameOfEnum(\n"
     150             :       "    $classname$_descriptor(), value);\n"
     151          41 :       "}\n");
     152             :     printer->Print(vars,
     153             :       "inline bool $classname$_Parse(\n"
     154             :       "    const ::std::string& name, $classname$* value) {\n"
     155             :       "  return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
     156             :       "    $classname$_descriptor(), name, value);\n"
     157          41 :       "}\n");
     158             :   }
     159          47 : }
     160             : 
     161          47 : void EnumGenerator::
     162             : GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
     163             :   printer->Print(
     164             :       "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
     165             :       "{};\n",
     166         141 :       "classname", ClassName(descriptor_, true));
     167         141 :   if (HasDescriptorMethods(descriptor_->file())) {
     168             :     printer->Print(
     169             :       "template <>\n"
     170             :       "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
     171             :       "  return $classname$_descriptor();\n"
     172             :       "}\n",
     173          82 :       "classname", ClassName(descriptor_, true));
     174             :   }
     175          47 : }
     176             : 
     177          17 : void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
     178             :   map<string, string> vars;
     179         168 :   vars["nested_name"] = descriptor_->name();
     180          34 :   vars["classname"] = classname_;
     181          17 :   printer->Print(vars, "typedef $classname$ $nested_name$;\n");
     182             : 
     183         117 :   for (int j = 0; j < descriptor_->value_count(); j++) {
     184         200 :     vars["tag"] = EnumValueName(descriptor_->value(j));
     185             :     printer->Print(vars,
     186          50 :       "static const $nested_name$ $tag$ = $classname$_$tag$;\n");
     187             :   }
     188             : 
     189             :   printer->Print(vars,
     190             :     "static inline bool $nested_name$_IsValid(int value) {\n"
     191             :     "  return $classname$_IsValid(value);\n"
     192             :     "}\n"
     193             :     "static const $nested_name$ $nested_name$_MIN =\n"
     194             :     "  $classname$_$nested_name$_MIN;\n"
     195             :     "static const $nested_name$ $nested_name$_MAX =\n"
     196          17 :     "  $classname$_$nested_name$_MAX;\n");
     197          17 :   if (generate_array_size_) {
     198             :     printer->Print(vars,
     199             :       "static const int $nested_name$_ARRAYSIZE =\n"
     200          16 :       "  $classname$_$nested_name$_ARRAYSIZE;\n");
     201             :   }
     202             : 
     203          51 :   if (HasDescriptorMethods(descriptor_->file())) {
     204             :     printer->Print(vars,
     205             :       "static inline const ::google::protobuf::EnumDescriptor*\n"
     206             :       "$nested_name$_descriptor() {\n"
     207             :       "  return $classname$_descriptor();\n"
     208          16 :       "}\n");
     209             :     printer->Print(vars,
     210             :       "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
     211             :       "  return $classname$_Name(value);\n"
     212          16 :       "}\n");
     213             :     printer->Print(vars,
     214             :       "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
     215             :       "    $nested_name$* value) {\n"
     216             :       "  return $classname$_Parse(name, value);\n"
     217          16 :       "}\n");
     218             :   }
     219          17 : }
     220             : 
     221          41 : void EnumGenerator::GenerateDescriptorInitializer(
     222             :     io::Printer* printer, int index) {
     223             :   map<string, string> vars;
     224          82 :   vars["classname"] = classname_;
     225         123 :   vars["index"] = SimpleItoa(index);
     226             : 
     227          41 :   if (descriptor_->containing_type() == NULL) {
     228             :     printer->Print(vars,
     229          25 :       "$classname$_descriptor_ = file->enum_type($index$);\n");
     230             :   } else {
     231          48 :     vars["parent"] = ClassName(descriptor_->containing_type(), false);
     232             :     printer->Print(vars,
     233          16 :       "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
     234             :   }
     235          41 : }
     236             : 
     237          47 : void EnumGenerator::GenerateMethods(io::Printer* printer) {
     238             :   map<string, string> vars;
     239          94 :   vars["classname"] = classname_;
     240             : 
     241         625 :   if (HasDescriptorMethods(descriptor_->file())) {
     242             :     printer->Print(vars,
     243             :       "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
     244             :       "  protobuf_AssignDescriptorsOnce();\n"
     245             :       "  return $classname$_descriptor_;\n"
     246          41 :       "}\n");
     247             :   }
     248             : 
     249             :   printer->Print(vars,
     250             :     "bool $classname$_IsValid(int value) {\n"
     251          47 :     "  switch(value) {\n");
     252             : 
     253             :   // Multiple values may have the same number.  Make sure we only cover
     254             :   // each number once by first constructing a set containing all valid
     255             :   // numbers, then printing a case statement for each element.
     256             : 
     257             :   set<int> numbers;
     258         380 :   for (int j = 0; j < descriptor_->value_count(); j++) {
     259         286 :     const EnumValueDescriptor* value = descriptor_->value(j);
     260         286 :     numbers.insert(value->number());
     261             :   }
     262             : 
     263         235 :   for (set<int>::iterator iter = numbers.begin();
     264         188 :        iter != numbers.end(); ++iter) {
     265             :     printer->Print(
     266             :       "    case $number$:\n",
     267         282 :       "number", Int32ToString(*iter));
     268             :   }
     269             : 
     270             :   printer->Print(vars,
     271             :     "      return true;\n"
     272             :     "    default:\n"
     273             :     "      return false;\n"
     274             :     "  }\n"
     275             :     "}\n"
     276          47 :     "\n");
     277             : 
     278          94 :   if (descriptor_->containing_type() != NULL) {
     279             :     // We need to "define" the static constants which were declared in the
     280             :     // header, to give the linker a place to put them.  Or at least the C++
     281             :     // standard says we have to.  MSVC actually insists tha we do _not_ define
     282             :     // them again in the .cc file.
     283          17 :     printer->Print("#ifndef _MSC_VER\n");
     284             : 
     285          68 :     vars["parent"] = ClassName(descriptor_->containing_type(), false);
     286          51 :     vars["nested_name"] = descriptor_->name();
     287         134 :     for (int i = 0; i < descriptor_->value_count(); i++) {
     288         200 :       vars["value"] = EnumValueName(descriptor_->value(i));
     289             :       printer->Print(vars,
     290          50 :         "const $classname$ $parent$::$value$;\n");
     291             :     }
     292             :     printer->Print(vars,
     293             :       "const $classname$ $parent$::$nested_name$_MIN;\n"
     294          17 :       "const $classname$ $parent$::$nested_name$_MAX;\n");
     295          17 :     if (generate_array_size_) {
     296             :       printer->Print(vars,
     297          16 :         "const int $parent$::$nested_name$_ARRAYSIZE;\n");
     298             :     }
     299             : 
     300          17 :     printer->Print("#endif  // _MSC_VER\n");
     301             :   }
     302          47 : }
     303             : 
     304             : }  // namespace cpp
     305             : }  // namespace compiler
     306             : }  // namespace protobuf
     307             : }  // namespace google

Generated by: LCOV version 1.10