Imported Upstream version 3.8.0
[platform/upstream/protobuf.git] / src / google / protobuf / compiler / cpp / cpp_enum.cc
index 0d6a9e2..5e2ac25 100644 (file)
@@ -46,7 +46,7 @@ namespace cpp {
 
 namespace {
 // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
-// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
 // generation of the GOOGLE_ARRAYSIZE constant.
 bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
   int32 max_value = descriptor->value(0)->number();
@@ -55,61 +55,52 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
       max_value = descriptor->value(i)->number();
     }
   }
-  return max_value != ::google::protobuf::kint32max;
+  return max_value != kint32max;
 }
 }  // namespace
 
 EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
+                             const std::map<std::string, std::string>& vars,
                              const Options& options)
-  : descriptor_(descriptor),
-    classname_(ClassName(descriptor, false)),
-    options_(options),
-    generate_array_size_(ShouldGenerateArraySize(descriptor)) {
+    : descriptor_(descriptor),
+      classname_(ClassName(descriptor, false)),
+      options_(options),
+      generate_array_size_(ShouldGenerateArraySize(descriptor)),
+      variables_(vars) {
+  variables_["classname"] = classname_;
+  variables_["classtype"] = QualifiedClassName(descriptor_, options);
+  variables_["short_name"] = descriptor_->name();
+  variables_["nested_name"] = descriptor_->name();
+  variables_["resolved_name"] = ResolveKeyword(descriptor_->name());
+  variables_["prefix"] =
+      (descriptor_->containing_type() == NULL) ? "" : classname_ + "_";
 }
 
 EnumGenerator::~EnumGenerator() {}
 
-void EnumGenerator::FillForwardDeclaration(
-    std::map<string, const EnumDescriptor*>* enum_names) {
-  if (!options_.proto_h) {
-    return;
-  }
-  (*enum_names)[classname_] = descriptor_;
-}
-
 void EnumGenerator::GenerateDefinition(io::Printer* printer) {
-  std::map<string, string> vars;
-  vars["classname"] = classname_;
-  vars["short_name"] = descriptor_->name();
-  vars["enumbase"] = options_.proto_h ? " : int" : "";
-  // These variables are placeholders to pick out the beginning and ends of
-  // identifiers for annotations (when doing so with existing variables would
-  // be ambiguous or impossible). They should never be set to anything but the
-  // empty string.
-  vars["{"] = "";
-  vars["}"] = "";
-
-  printer->Print(vars, "enum $classname$$enumbase$ {\n");
-  printer->Annotate("classname", descriptor_);
-  printer->Indent();
+  Formatter format(printer, variables_);
+  format("enum ${1$$classname$$}$ : int {\n", descriptor_);
+  format.Indent();
 
   const EnumValueDescriptor* min_value = descriptor_->value(0);
   const EnumValueDescriptor* max_value = descriptor_->value(0);
 
   for (int i = 0; i < descriptor_->value_count(); i++) {
-    vars["name"] = EnumValueName(descriptor_->value(i));
+    auto format_value = format;
+    format_value.Set("name", EnumValueName(descriptor_->value(i)));
     // In C++, an value of -2147483648 gets interpreted as the negative of
     // 2147483648, and since 2147483648 can't fit in an integer, this produces a
     // compiler warning.  This works around that issue.
-    vars["number"] = Int32ToString(descriptor_->value(i)->number());
-    vars["prefix"] = (descriptor_->containing_type() == NULL) ?
-      "" : classname_ + "_";
-    vars["deprecation"] = descriptor_->value(i)->options().deprecated() ?
-        " PROTOBUF_DEPRECATED" : "";
+    format_value.Set("number", Int32ToString(descriptor_->value(i)->number()));
+    format_value.Set(
+        "deprecation",
+        DeprecatedAttribute(options_,
+                            descriptor_->value(i)->options().deprecated()));
 
-    if (i > 0) printer->Print(",\n");
-    printer->Print(vars, "${$$prefix$$name$$}$$deprecation$ = $number$");
-    printer->Annotate("{", "}", descriptor_->value(i));
+    if (i > 0) format_value(",\n");
+    format_value("${1$$prefix$$name$$}$ $deprecation$= $number$",
+                 descriptor_->value(i));
 
     if (descriptor_->value(i)->number() < min_value->number()) {
       min_value = descriptor_->value(i);
@@ -119,156 +110,146 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
     }
   }
 
-  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+  if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
     // For new enum semantics: generate min and max sentinel values equal to
     // INT32_MIN and INT32_MAX
-    if (descriptor_->value_count() > 0) printer->Print(",\n");
-    printer->Print(vars,
-        "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n"
-        "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max");
+    if (descriptor_->value_count() > 0) format(",\n");
+    format(
+        "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = "
+        "std::numeric_limits<$int32$>::min(),\n"
+        "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = "
+        "std::numeric_limits<$int32$>::max()");
   }
 
-  printer->Outdent();
-  printer->Print("\n};\n");
+  format.Outdent();
+  format("\n};\n");
 
-  vars["min_name"] = EnumValueName(min_value);
-  vars["max_name"] = EnumValueName(max_value);
-
-  if (options_.dllexport_decl.empty()) {
-    vars["dllexport"] = "";
-  } else {
-    vars["dllexport"] = options_.dllexport_decl + " ";
-  }
-
-  printer->Print(vars,
-                 "$dllexport$bool $classname$_IsValid(int value);\n"
-                 "const $classname$ ${$$prefix$$short_name$_MIN$}$ = "
-                 "$prefix$$min_name$;\n");
-  printer->Annotate("{", "}", descriptor_);
-  printer->Print(vars,
-                 "const $classname$ ${$$prefix$$short_name$_MAX$}$ = "
-                 "$prefix$$max_name$;\n");
-  printer->Annotate("{", "}", descriptor_);
+  format(
+      "$dllexport_decl $bool $classname$_IsValid(int value);\n"
+      "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = "
+      "$prefix$$2$;\n"
+      "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = "
+      "$prefix$$3$;\n",
+      descriptor_, EnumValueName(min_value), EnumValueName(max_value));
 
   if (generate_array_size_) {
-    printer->Print(vars,
-                   "const int ${$$prefix$$short_name$_ARRAYSIZE$}$ = "
-                   "$prefix$$short_name$_MAX + 1;\n\n");
-    printer->Annotate("{", "}", descriptor_);
+    format(
+        "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = "
+        "$prefix$$short_name$_MAX + 1;\n\n",
+        descriptor_);
   }
 
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    printer->Print(vars,
-      "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
+    format(
+        "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* "
+        "$classname$_descriptor();\n");
     // The _Name and _Parse methods
-    printer->Print(
-        vars,
-        "inline const ::std::string& $classname$_Name($classname$ value) {\n"
-        "  return ::google::protobuf::internal::NameOfEnum(\n"
-        "    $classname$_descriptor(), value);\n"
+    // Support a stricter, type-checked enum-to-string method that
+    // statically checks whether the parameter is the exact enum type or is
+    // an integral type.
+    format(
+        "template<typename T>\n"
+        "inline const std::string& $classname$_Name(T enum_t_value) {\n"
+        "  static_assert(::std::is_same<T, $classname$>::value ||\n"
+        "    ::std::is_integral<T>::value,\n"
+        "    \"Incorrect type passed to function $classname$_Name.\");\n"
+        "  return ::$proto_ns$::internal::NameOfEnum(\n"
+        "    $classname$_descriptor(), enum_t_value);\n"
+        "}\n");
+    format(
+        "inline bool $classname$_Parse(\n"
+        "    const std::string& name, $classname$* value) {\n"
+        "  return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n"
+        "    $classname$_descriptor(), name, value);\n"
         "}\n");
-    printer->Print(vars,
-      "inline bool $classname$_Parse(\n"
-      "    const ::std::string& name, $classname$* value) {\n"
-      "  return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
-      "    $classname$_descriptor(), name, value);\n"
-      "}\n");
   }
 }
 
-void EnumGenerator::
-GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
-  printer->Print(
-      "template <> struct is_proto_enum< $classname$> : ::std::true_type "
-      "{};\n",
-      "classname", ClassName(descriptor_, true));
+void EnumGenerator::GenerateGetEnumDescriptorSpecializations(
+    io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format(
+      "template <> struct is_proto_enum< $classtype$> : ::std::true_type "
+      "{};\n");
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    printer->Print(
-      "template <>\n"
-      "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
-      "  return $classname$_descriptor();\n"
-      "}\n",
-      "classname", ClassName(descriptor_, true));
+    format(
+        "template <>\n"
+        "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n"
+        "  return $classtype$_descriptor();\n"
+        "}\n");
   }
 }
 
-void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
-  std::map<string, string> vars;
-  vars["nested_name"] = descriptor_->name();
-  vars["classname"] = classname_;
-  vars["constexpr"] = options_.proto_h ? "constexpr " : "";
-  vars["{"] = "";
-  vars["}"] = "";
-  printer->Print(vars, "typedef $classname$ $nested_name$;\n");
+void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("typedef $classname$ $resolved_name$;\n");
 
   for (int j = 0; j < descriptor_->value_count(); j++) {
-    vars["tag"] = EnumValueName(descriptor_->value(j));
-    vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ?
-      "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
-    printer->Print(vars,
-      "$deprecated_attr$static $constexpr$const $nested_name$ ${$$tag$$}$ =\n"
-      "  $classname$_$tag$;\n");
-    printer->Annotate("{", "}", descriptor_->value(j));
+    std::string deprecated_attr = DeprecatedAttribute(
+        options_, descriptor_->value(j)->options().deprecated());
+    format(
+        "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n"
+        "  $classname$_$3$;\n",
+        deprecated_attr, descriptor_->value(j),
+        EnumValueName(descriptor_->value(j)));
   }
 
-  printer->Print(vars,
-    "static inline bool $nested_name$_IsValid(int value) {\n"
-    "  return $classname$_IsValid(value);\n"
-    "}\n"
-    "static const $nested_name$ ${$$nested_name$_MIN$}$ =\n"
-    "  $classname$_$nested_name$_MIN;\n");
-  printer->Annotate("{", "}", descriptor_);
-  printer->Print(vars,
-    "static const $nested_name$ ${$$nested_name$_MAX$}$ =\n"
-    "  $classname$_$nested_name$_MAX;\n");
-  printer->Annotate("{", "}", descriptor_);
+  format(
+      "static inline bool $nested_name$_IsValid(int value) {\n"
+      "  return $classname$_IsValid(value);\n"
+      "}\n"
+      "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n"
+      "  $classname$_$nested_name$_MIN;\n"
+      "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n"
+      "  $classname$_$nested_name$_MAX;\n",
+      descriptor_);
   if (generate_array_size_) {
-    printer->Print(vars,
-      "static const int ${$$nested_name$_ARRAYSIZE$}$ =\n"
-      "  $classname$_$nested_name$_ARRAYSIZE;\n");
-    printer->Annotate("{", "}", descriptor_);
+    format(
+        "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n"
+        "  $classname$_$nested_name$_ARRAYSIZE;\n",
+        descriptor_);
   }
 
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    printer->Print(vars,
-      "static inline const ::google::protobuf::EnumDescriptor*\n"
-      "$nested_name$_descriptor() {\n"
-      "  return $classname$_descriptor();\n"
-      "}\n");
-    printer->Print(vars,
-                   "static inline const ::std::string& "
-                   "$nested_name$_Name($nested_name$ value) {"
-                   "\n"
-                   "  return $classname$_Name(value);\n"
-                   "}\n");
-    printer->Print(vars,
-      "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
-      "    $nested_name$* value) {\n"
-      "  return $classname$_Parse(name, value);\n"
-      "}\n");
+    format(
+        "static inline const ::$proto_ns$::EnumDescriptor*\n"
+        "$nested_name$_descriptor() {\n"
+        "  return $classname$_descriptor();\n"
+        "}\n");
+    // Support a stricter, type-checked enum-to-string method that
+    // statically checks whether the parameter is the exact enum type or is
+    // an integral type.
+    format(
+        "template<typename T>\n"
+        "static inline const std::string& $nested_name$_Name(T enum_t_value) "
+        "{\n"
+        "  static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
+        "    ::std::is_integral<T>::value,\n"
+        "    \"Incorrect type passed to function $nested_name$_Name.\");\n"
+        "  return $classname$_Name(enum_t_value);\n"
+        "}\n");
+    format(
+        "static inline bool $nested_name$_Parse(const std::string& name,\n"
+        "    $resolved_name$* value) {\n"
+        "  return $classname$_Parse(name, value);\n"
+        "}\n");
   }
 }
 
 void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
-  std::map<string, string> vars;
-  vars["classname"] = classname_;
-  vars["index_in_metadata"] = SimpleItoa(idx);
-  vars["constexpr"] = options_.proto_h ? "constexpr " : "";
-  vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name());
-
+  Formatter format(printer, variables_);
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    printer->Print(
-        vars,
-        "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
-        "  $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
-        "  return "
-        "$file_namespace$::file_level_enum_descriptors[$index_in_metadata$];\n"
-        "}\n");
+    format(
+        "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n"
+        "  ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n"
+        "  return $file_level_enum_descriptors$[$1$];\n"
+        "}\n",
+        idx);
   }
 
-  printer->Print(vars,
-    "bool $classname$_IsValid(int value) {\n"
-    "  switch (value) {\n");
+  format(
+      "bool $classname$_IsValid(int value) {\n"
+      "  switch (value) {\n");
 
   // Multiple values may have the same number.  Make sure we only cover
   // each number once by first constructing a set containing all valid
@@ -280,44 +261,43 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
     numbers.insert(value->number());
   }
 
-  for (std::set<int>::iterator iter = numbers.begin();
-       iter != numbers.end(); ++iter) {
-    printer->Print(
-      "    case $number$:\n",
-      "number", Int32ToString(*iter));
+  for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end();
+       ++iter) {
+    format("    case $1$:\n", Int32ToString(*iter));
   }
 
-  printer->Print(vars,
-    "      return true;\n"
-    "    default:\n"
-    "      return false;\n"
-    "  }\n"
-    "}\n"
-    "\n");
+  format(
+      "      return true;\n"
+      "    default:\n"
+      "      return false;\n"
+      "  }\n"
+      "}\n"
+      "\n");
 
   if (descriptor_->containing_type() != NULL) {
-    // We need to "define" the static constants which were declared in the
-    // header, to give the linker a place to put them.  Or at least the C++
-    // standard says we have to.  MSVC actually insists that we do _not_ define
-    // them again in the .cc file, prior to VC++ 2015.
-    printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
-
-    vars["parent"] = ClassName(descriptor_->containing_type(), false);
-    vars["nested_name"] = descriptor_->name();
+    std::string parent = ClassName(descriptor_->containing_type(), false);
+    // Before C++17, we must define the static constants which were
+    // declared in the header, to give the linker a place to put them.
+    // But pre-2015 MSVC++ insists that we not.
+    format(
+        "#if (__cplusplus < 201703) && "
+        "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
+
     for (int i = 0; i < descriptor_->value_count(); i++) {
-      vars["value"] = EnumValueName(descriptor_->value(i));
-      printer->Print(vars,
-        "$constexpr$const $classname$ $parent$::$value$;\n");
+      format("constexpr $classname$ $1$::$2$;\n", parent,
+             EnumValueName(descriptor_->value(i)));
     }
-    printer->Print(vars,
-      "const $classname$ $parent$::$nested_name$_MIN;\n"
-      "const $classname$ $parent$::$nested_name$_MAX;\n");
+    format(
+        "constexpr $classname$ $1$::$nested_name$_MIN;\n"
+        "constexpr $classname$ $1$::$nested_name$_MAX;\n",
+        parent);
     if (generate_array_size_) {
-      printer->Print(vars,
-        "const int $parent$::$nested_name$_ARRAYSIZE;\n");
+      format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent);
     }
 
-    printer->Print("#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
+    format(
+        "#endif  // (__cplusplus < 201703) && "
+        "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
   }
 }