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 <limits>
36#include <map>
37#include <vector>
38#include <google/protobuf/stubs/hash.h>
39
40#include <google/protobuf/compiler/cpp/cpp_helpers.h>
41#include <google/protobuf/io/printer.h>
42#include <google/protobuf/stubs/common.h>
43#include <google/protobuf/stubs/strutil.h>
44#include <google/protobuf/stubs/substitute.h>
45
46
47namespace google {
48namespace protobuf {
49namespace compiler {
50namespace cpp {
51
52namespace {
53
54string DotsToUnderscores(const string& name) {
55  return StringReplace(name, ".", "_", true);
56}
57
58string DotsToColons(const string& name) {
59  return StringReplace(name, ".", "::", true);
60}
61
62const char* const kKeywordList[] = {
63  "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
64  "catch", "char", "class", "compl", "const", "const_cast", "continue",
65  "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
66  "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
67  "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
68  "operator", "or", "or_eq", "private", "protected", "public", "register",
69  "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
70  "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
71  "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
72  "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
73};
74
75hash_set<string> MakeKeywordsMap() {
76  hash_set<string> result;
77  for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
78    result.insert(kKeywordList[i]);
79  }
80  return result;
81}
82
83hash_set<string> kKeywords = MakeKeywordsMap();
84
85// Returns whether the provided descriptor has an extension. This includes its
86// nested types.
87bool HasExtension(const Descriptor* descriptor) {
88  if (descriptor->extension_count() > 0) {
89    return true;
90  }
91  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
92    if (HasExtension(descriptor->nested_type(i))) {
93      return true;
94    }
95  }
96  return false;
97}
98
99}  // namespace
100
101string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
102  string result;
103  // Note:  I distrust ctype.h due to locales.
104  for (int i = 0; i < input.size(); i++) {
105    if ('a' <= input[i] && input[i] <= 'z') {
106      if (cap_next_letter) {
107        result += input[i] + ('A' - 'a');
108      } else {
109        result += input[i];
110      }
111      cap_next_letter = false;
112    } else if ('A' <= input[i] && input[i] <= 'Z') {
113      // Capital letters are left as-is.
114      result += input[i];
115      cap_next_letter = false;
116    } else if ('0' <= input[i] && input[i] <= '9') {
117      result += input[i];
118      cap_next_letter = true;
119    } else {
120      cap_next_letter = true;
121    }
122  }
123  return result;
124}
125
126const char kThickSeparator[] =
127  "// ===================================================================\n";
128const char kThinSeparator[] =
129  "// -------------------------------------------------------------------\n";
130
131string ClassName(const Descriptor* descriptor, bool qualified) {
132
133  // Find "outer", the descriptor of the top-level message in which
134  // "descriptor" is embedded.
135  const Descriptor* outer = descriptor;
136  while (outer->containing_type() != NULL) outer = outer->containing_type();
137
138  const string& outer_name = outer->full_name();
139  string inner_name = descriptor->full_name().substr(outer_name.size());
140
141  if (qualified) {
142    return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
143  } else {
144    return outer->name() + DotsToUnderscores(inner_name);
145  }
146}
147
148string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
149  if (enum_descriptor->containing_type() == NULL) {
150    if (qualified) {
151      return "::" + DotsToColons(enum_descriptor->full_name());
152    } else {
153      return enum_descriptor->name();
154    }
155  } else {
156    string result = ClassName(enum_descriptor->containing_type(), qualified);
157    result += '_';
158    result += enum_descriptor->name();
159    return result;
160  }
161}
162
163
164string SuperClassName(const Descriptor* descriptor) {
165  return HasDescriptorMethods(descriptor->file()) ?
166      "::google::protobuf::Message" : "::google::protobuf::MessageLite";
167}
168
169string FieldName(const FieldDescriptor* field) {
170  string result = field->name();
171  LowerString(&result);
172  if (kKeywords.count(result) > 0) {
173    result.append("_");
174  }
175  return result;
176}
177
178string FieldConstantName(const FieldDescriptor *field) {
179  string field_name = UnderscoresToCamelCase(field->name(), true);
180  string result = "k" + field_name + "FieldNumber";
181
182  if (!field->is_extension() &&
183      field->containing_type()->FindFieldByCamelcaseName(
184        field->camelcase_name()) != field) {
185    // This field's camelcase name is not unique.  As a hack, add the field
186    // number to the constant name.  This makes the constant rather useless,
187    // but what can we do?
188    result += "_" + SimpleItoa(field->number());
189  }
190
191  return result;
192}
193
194string FieldMessageTypeName(const FieldDescriptor* field) {
195  // Note:  The Google-internal version of Protocol Buffers uses this function
196  //   as a hook point for hacks to support legacy code.
197  return ClassName(field->message_type(), true);
198}
199
200string StripProto(const string& filename) {
201  if (HasSuffixString(filename, ".protodevel")) {
202    return StripSuffixString(filename, ".protodevel");
203  } else {
204    return StripSuffixString(filename, ".proto");
205  }
206}
207
208const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
209  switch (type) {
210    case FieldDescriptor::CPPTYPE_INT32  : return "::google::protobuf::int32";
211    case FieldDescriptor::CPPTYPE_INT64  : return "::google::protobuf::int64";
212    case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
213    case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
214    case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
215    case FieldDescriptor::CPPTYPE_FLOAT  : return "float";
216    case FieldDescriptor::CPPTYPE_BOOL   : return "bool";
217    case FieldDescriptor::CPPTYPE_ENUM   : return "int";
218    case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
219    case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
220
221    // No default because we want the compiler to complain if any new
222    // CppTypes are added.
223  }
224
225  GOOGLE_LOG(FATAL) << "Can't get here.";
226  return NULL;
227}
228
229const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
230  switch (type) {
231    case FieldDescriptor::TYPE_INT32   : return "Int32";
232    case FieldDescriptor::TYPE_INT64   : return "Int64";
233    case FieldDescriptor::TYPE_UINT32  : return "UInt32";
234    case FieldDescriptor::TYPE_UINT64  : return "UInt64";
235    case FieldDescriptor::TYPE_SINT32  : return "SInt32";
236    case FieldDescriptor::TYPE_SINT64  : return "SInt64";
237    case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
238    case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
239    case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
240    case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
241    case FieldDescriptor::TYPE_FLOAT   : return "Float";
242    case FieldDescriptor::TYPE_DOUBLE  : return "Double";
243
244    case FieldDescriptor::TYPE_BOOL    : return "Bool";
245    case FieldDescriptor::TYPE_ENUM    : return "Enum";
246
247    case FieldDescriptor::TYPE_STRING  : return "String";
248    case FieldDescriptor::TYPE_BYTES   : return "Bytes";
249    case FieldDescriptor::TYPE_GROUP   : return "Group";
250    case FieldDescriptor::TYPE_MESSAGE : return "Message";
251
252    // No default because we want the compiler to complain if any new
253    // types are added.
254  }
255  GOOGLE_LOG(FATAL) << "Can't get here.";
256  return "";
257}
258
259string Int32ToString(int number) {
260  // gcc rejects the decimal form of kint32min.
261  if (number == kint32min) {
262    GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
263    return "(~0x7fffffff)";
264  } else {
265    return SimpleItoa(number);
266  }
267}
268
269string Int64ToString(int64 number) {
270  // gcc rejects the decimal form of kint64min
271  if (number == kint64min) {
272    // Make sure we are in a 2's complement system.
273    GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff),
274                   kint64min_value_error);
275    return "GOOGLE_LONGLONG(~0x7fffffffffffffff)";
276  }
277  return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
278}
279
280string DefaultValue(const FieldDescriptor* field) {
281  switch (field->cpp_type()) {
282    case FieldDescriptor::CPPTYPE_INT32:
283      return Int32ToString(field->default_value_int32());
284    case FieldDescriptor::CPPTYPE_UINT32:
285      return SimpleItoa(field->default_value_uint32()) + "u";
286    case FieldDescriptor::CPPTYPE_INT64:
287      return Int64ToString(field->default_value_int64());
288    case FieldDescriptor::CPPTYPE_UINT64:
289      return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
290    case FieldDescriptor::CPPTYPE_DOUBLE: {
291      double value = field->default_value_double();
292      if (value == numeric_limits<double>::infinity()) {
293        return "::google::protobuf::internal::Infinity()";
294      } else if (value == -numeric_limits<double>::infinity()) {
295        return "-::google::protobuf::internal::Infinity()";
296      } else if (value != value) {
297        return "::google::protobuf::internal::NaN()";
298      } else {
299        return SimpleDtoa(value);
300      }
301    }
302    case FieldDescriptor::CPPTYPE_FLOAT:
303      {
304        float value = field->default_value_float();
305        if (value == numeric_limits<float>::infinity()) {
306          return "static_cast<float>(::google::protobuf::internal::Infinity())";
307        } else if (value == -numeric_limits<float>::infinity()) {
308          return "static_cast<float>(-::google::protobuf::internal::Infinity())";
309        } else if (value != value) {
310          return "static_cast<float>(::google::protobuf::internal::NaN())";
311        } else {
312          string float_value = SimpleFtoa(value);
313          // If floating point value contains a period (.) or an exponent
314          // (either E or e), then append suffix 'f' to make it a float
315          // literal.
316          if (float_value.find_first_of(".eE") != string::npos) {
317            float_value.push_back('f');
318          }
319          return float_value;
320        }
321      }
322    case FieldDescriptor::CPPTYPE_BOOL:
323      return field->default_value_bool() ? "true" : "false";
324    case FieldDescriptor::CPPTYPE_ENUM:
325      // Lazy:  Generate a static_cast because we don't have a helper function
326      //   that constructs the full name of an enum value.
327      return strings::Substitute(
328          "static_cast< $0 >($1)",
329          ClassName(field->enum_type(), true),
330          Int32ToString(field->default_value_enum()->number()));
331    case FieldDescriptor::CPPTYPE_STRING:
332      return "\"" + EscapeTrigraphs(
333        CEscape(field->default_value_string())) +
334        "\"";
335    case FieldDescriptor::CPPTYPE_MESSAGE:
336      return FieldMessageTypeName(field) + "::default_instance()";
337  }
338  // Can't actually get here; make compiler happy.  (We could add a default
339  // case above but then we wouldn't get the nice compiler warning when a
340  // new type is added.)
341  GOOGLE_LOG(FATAL) << "Can't get here.";
342  return "";
343}
344
345// Convert a file name into a valid identifier.
346string FilenameIdentifier(const string& filename) {
347  string result;
348  for (int i = 0; i < filename.size(); i++) {
349    if (ascii_isalnum(filename[i])) {
350      result.push_back(filename[i]);
351    } else {
352      // Not alphanumeric.  To avoid any possibility of name conflicts we
353      // use the hex code for the character.
354      result.push_back('_');
355      char buffer[kFastToBufferSize];
356      result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
357    }
358  }
359  return result;
360}
361
362// Return the name of the AddDescriptors() function for a given file.
363string GlobalAddDescriptorsName(const string& filename) {
364  return "protobuf_AddDesc_" + FilenameIdentifier(filename);
365}
366
367// Return the name of the AssignDescriptors() function for a given file.
368string GlobalAssignDescriptorsName(const string& filename) {
369  return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
370}
371
372// Return the name of the ShutdownFile() function for a given file.
373string GlobalShutdownFileName(const string& filename) {
374  return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
375}
376
377// Return the qualified C++ name for a file level symbol.
378string QualifiedFileLevelSymbol(const string& package, const string& name) {
379  if (package.empty()) {
380    return StrCat("::", name);
381  }
382  return StrCat("::", DotsToColons(package), "::", name);
383}
384
385// Escape C++ trigraphs by escaping question marks to \?
386string EscapeTrigraphs(const string& to_escape) {
387  return StringReplace(to_escape, "?", "\\?", true);
388}
389
390// Escaped function name to eliminate naming conflict.
391string SafeFunctionName(const Descriptor* descriptor,
392                        const FieldDescriptor* field,
393                        const string& prefix) {
394  // Do not use FieldName() since it will escape keywords.
395  string name = field->name();
396  LowerString(&name);
397  string function_name = prefix + name;
398  if (descriptor->FindFieldByName(function_name)) {
399    // Single underscore will also make it conflicting with the private data
400    // member. We use double underscore to escape function names.
401    function_name.append("__");
402  } else if (kKeywords.count(name) > 0) {
403    // If the field name is a keyword, we append the underscore back to keep it
404    // consistent with other function names.
405    function_name.append("_");
406  }
407  return function_name;
408}
409
410bool StaticInitializersForced(const FileDescriptor* file) {
411  if (HasDescriptorMethods(file) || file->extension_count() > 0) {
412    return true;
413  }
414  for (int i = 0; i < file->message_type_count(); ++i) {
415    if (HasExtension(file->message_type(i))) {
416      return true;
417    }
418  }
419  return false;
420}
421
422void PrintHandlingOptionalStaticInitializers(
423    const FileDescriptor* file, io::Printer* printer,
424    const char* with_static_init, const char* without_static_init,
425    const char* var1, const string& val1,
426    const char* var2, const string& val2) {
427  map<string, string> vars;
428  if (var1) {
429    vars[var1] = val1;
430  }
431  if (var2) {
432    vars[var2] = val2;
433  }
434  PrintHandlingOptionalStaticInitializers(
435      vars, file, printer, with_static_init, without_static_init);
436}
437
438void PrintHandlingOptionalStaticInitializers(
439    const map<string, string>& vars, const FileDescriptor* file,
440    io::Printer* printer, const char* with_static_init,
441    const char* without_static_init) {
442  if (StaticInitializersForced(file)) {
443    printer->Print(vars, with_static_init);
444  } else {
445    printer->Print(vars, (string(
446      "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") +
447      without_static_init +
448      "#else\n" +
449      with_static_init +
450      "#endif\n").c_str());
451  }
452}
453
454
455static bool HasEnumDefinitions(const Descriptor* message_type) {
456  if (message_type->enum_type_count() > 0) return true;
457  for (int i = 0; i < message_type->nested_type_count(); ++i) {
458    if (HasEnumDefinitions(message_type->nested_type(i))) return true;
459  }
460  return false;
461}
462
463bool HasEnumDefinitions(const FileDescriptor* file) {
464  if (file->enum_type_count() > 0) return true;
465  for (int i = 0; i < file->message_type_count(); ++i) {
466    if (HasEnumDefinitions(file->message_type(i))) return true;
467  }
468  return false;
469}
470
471bool IsStringOrMessage(const FieldDescriptor* field) {
472  switch (field->cpp_type()) {
473    case FieldDescriptor::CPPTYPE_INT32:
474    case FieldDescriptor::CPPTYPE_INT64:
475    case FieldDescriptor::CPPTYPE_UINT32:
476    case FieldDescriptor::CPPTYPE_UINT64:
477    case FieldDescriptor::CPPTYPE_DOUBLE:
478    case FieldDescriptor::CPPTYPE_FLOAT:
479    case FieldDescriptor::CPPTYPE_BOOL:
480    case FieldDescriptor::CPPTYPE_ENUM:
481      return false;
482    case FieldDescriptor::CPPTYPE_STRING:
483    case FieldDescriptor::CPPTYPE_MESSAGE:
484      return true;
485  }
486
487  GOOGLE_LOG(FATAL) << "Can't get here.";
488  return false;
489}
490
491}  // namespace cpp
492}  // namespace compiler
493}  // namespace protobuf
494}  // namespace google
495