cpp_enum.cc 12 KB

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