blob: 237278dba1ea937a22082be5768ec3324c3452ce [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
kenton@google.comfccb1462009-12-18 02:11:36 +000035#include <limits>
pliard@google.com6103d4e2012-05-04 11:16:09 +000036#include <map>
temporal40ee5512008-07-10 02:12:20 +000037#include <vector>
38#include <google/protobuf/stubs/hash.h>
39
40#include <google/protobuf/compiler/cpp/cpp_helpers.h>
pliard@google.com6103d4e2012-05-04 11:16:09 +000041#include <google/protobuf/io/printer.h>
temporal40ee5512008-07-10 02:12:20 +000042#include <google/protobuf/stubs/common.h>
43#include <google/protobuf/stubs/strutil.h>
kenton@google.comd37d46d2009-04-25 02:53:47 +000044#include <google/protobuf/stubs/substitute.h>
temporal40ee5512008-07-10 02:12:20 +000045
kenton@google.comfccb1462009-12-18 02:11:36 +000046
temporal40ee5512008-07-10 02:12:20 +000047namespace 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[] = {
Feng Xiao6ef984a2014-11-10 17:34:54 -080063 "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
64 "bool", "break", "case", "catch", "char", "class", "compl", "const",
65 "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
66 "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
67 "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
68 "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or",
69 "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
70 "return", "short", "signed", "sizeof", "static", "static_assert",
71 "static_cast", "struct", "switch", "template", "this", "thread_local",
72 "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
73 "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
temporal40ee5512008-07-10 02:12:20 +000074};
75
76hash_set<string> MakeKeywordsMap() {
77 hash_set<string> result;
78 for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
79 result.insert(kKeywordList[i]);
80 }
81 return result;
82}
83
84hash_set<string> kKeywords = MakeKeywordsMap();
85
jieluo@google.com4de8f552014-07-18 00:47:59 +000086// Returns whether the provided descriptor has an extension. This includes its
87// nested types.
88bool HasExtension(const Descriptor* descriptor) {
89 if (descriptor->extension_count() > 0) {
90 return true;
91 }
92 for (int i = 0; i < descriptor->nested_type_count(); ++i) {
93 if (HasExtension(descriptor->nested_type(i))) {
94 return true;
95 }
96 }
97 return false;
98}
99
100} // namespace
101
kenton@google.comcfa2d8a2009-04-18 00:02:12 +0000102string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
103 string result;
104 // Note: I distrust ctype.h due to locales.
105 for (int i = 0; i < input.size(); i++) {
106 if ('a' <= input[i] && input[i] <= 'z') {
107 if (cap_next_letter) {
108 result += input[i] + ('A' - 'a');
109 } else {
110 result += input[i];
111 }
112 cap_next_letter = false;
113 } else if ('A' <= input[i] && input[i] <= 'Z') {
114 // Capital letters are left as-is.
115 result += input[i];
116 cap_next_letter = false;
117 } else if ('0' <= input[i] && input[i] <= '9') {
118 result += input[i];
119 cap_next_letter = true;
120 } else {
121 cap_next_letter = true;
122 }
123 }
124 return result;
125}
126
temporal40ee5512008-07-10 02:12:20 +0000127const char kThickSeparator[] =
128 "// ===================================================================\n";
129const char kThinSeparator[] =
130 "// -------------------------------------------------------------------\n";
131
132string ClassName(const Descriptor* descriptor, bool qualified) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000133
temporal40ee5512008-07-10 02:12:20 +0000134 // Find "outer", the descriptor of the top-level message in which
135 // "descriptor" is embedded.
136 const Descriptor* outer = descriptor;
137 while (outer->containing_type() != NULL) outer = outer->containing_type();
138
139 const string& outer_name = outer->full_name();
140 string inner_name = descriptor->full_name().substr(outer_name.size());
141
142 if (qualified) {
143 return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
144 } else {
145 return outer->name() + DotsToUnderscores(inner_name);
146 }
147}
148
149string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
150 if (enum_descriptor->containing_type() == NULL) {
151 if (qualified) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000152 return "::" + DotsToColons(enum_descriptor->full_name());
temporal40ee5512008-07-10 02:12:20 +0000153 } else {
154 return enum_descriptor->name();
155 }
156 } else {
157 string result = ClassName(enum_descriptor->containing_type(), qualified);
158 result += '_';
159 result += enum_descriptor->name();
160 return result;
161 }
162}
163
kenton@google.comfccb1462009-12-18 02:11:36 +0000164
165string SuperClassName(const Descriptor* descriptor) {
166 return HasDescriptorMethods(descriptor->file()) ?
167 "::google::protobuf::Message" : "::google::protobuf::MessageLite";
168}
169
temporal40ee5512008-07-10 02:12:20 +0000170string FieldName(const FieldDescriptor* field) {
171 string result = field->name();
172 LowerString(&result);
173 if (kKeywords.count(result) > 0) {
174 result.append("_");
175 }
176 return result;
177}
178
kenton@google.comcfa2d8a2009-04-18 00:02:12 +0000179string FieldConstantName(const FieldDescriptor *field) {
180 string field_name = UnderscoresToCamelCase(field->name(), true);
kenton@google.com80b1d622009-07-29 01:13:20 +0000181 string result = "k" + field_name + "FieldNumber";
182
183 if (!field->is_extension() &&
184 field->containing_type()->FindFieldByCamelcaseName(
185 field->camelcase_name()) != field) {
186 // This field's camelcase name is not unique. As a hack, add the field
187 // number to the constant name. This makes the constant rather useless,
188 // but what can we do?
189 result += "_" + SimpleItoa(field->number());
190 }
191
192 return result;
kenton@google.comcfa2d8a2009-04-18 00:02:12 +0000193}
194
kenton@google.comfccb1462009-12-18 02:11:36 +0000195string FieldMessageTypeName(const FieldDescriptor* field) {
196 // Note: The Google-internal version of Protocol Buffers uses this function
197 // as a hook point for hacks to support legacy code.
198 return ClassName(field->message_type(), true);
199}
200
temporal40ee5512008-07-10 02:12:20 +0000201string StripProto(const string& filename) {
202 if (HasSuffixString(filename, ".protodevel")) {
203 return StripSuffixString(filename, ".protodevel");
204 } else {
205 return StripSuffixString(filename, ".proto");
206 }
207}
208
209const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
210 switch (type) {
211 case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32";
212 case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64";
213 case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
214 case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
215 case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
216 case FieldDescriptor::CPPTYPE_FLOAT : return "float";
217 case FieldDescriptor::CPPTYPE_BOOL : return "bool";
218 case FieldDescriptor::CPPTYPE_ENUM : return "int";
219 case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
220 case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
221
222 // No default because we want the compiler to complain if any new
223 // CppTypes are added.
224 }
225
226 GOOGLE_LOG(FATAL) << "Can't get here.";
227 return NULL;
228}
229
230const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
231 switch (type) {
232 case FieldDescriptor::TYPE_INT32 : return "Int32";
233 case FieldDescriptor::TYPE_INT64 : return "Int64";
234 case FieldDescriptor::TYPE_UINT32 : return "UInt32";
235 case FieldDescriptor::TYPE_UINT64 : return "UInt64";
236 case FieldDescriptor::TYPE_SINT32 : return "SInt32";
237 case FieldDescriptor::TYPE_SINT64 : return "SInt64";
238 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
239 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
240 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
241 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
242 case FieldDescriptor::TYPE_FLOAT : return "Float";
243 case FieldDescriptor::TYPE_DOUBLE : return "Double";
244
245 case FieldDescriptor::TYPE_BOOL : return "Bool";
246 case FieldDescriptor::TYPE_ENUM : return "Enum";
247
248 case FieldDescriptor::TYPE_STRING : return "String";
249 case FieldDescriptor::TYPE_BYTES : return "Bytes";
250 case FieldDescriptor::TYPE_GROUP : return "Group";
251 case FieldDescriptor::TYPE_MESSAGE : return "Message";
252
253 // No default because we want the compiler to complain if any new
254 // types are added.
255 }
256 GOOGLE_LOG(FATAL) << "Can't get here.";
257 return "";
258}
259
jieluo@google.com4de8f552014-07-18 00:47:59 +0000260string Int32ToString(int number) {
261 // gcc rejects the decimal form of kint32min.
262 if (number == kint32min) {
263 GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
264 return "(~0x7fffffff)";
265 } else {
266 return SimpleItoa(number);
267 }
268}
269
270string Int64ToString(int64 number) {
271 // gcc rejects the decimal form of kint64min
272 if (number == kint64min) {
273 // Make sure we are in a 2's complement system.
jieluo@google.come6726e22014-07-23 23:37:26 +0000274 GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000275 kint64min_value_error);
jieluo@google.come6726e22014-07-23 23:37:26 +0000276 return "GOOGLE_LONGLONG(~0x7fffffffffffffff)";
jieluo@google.com4de8f552014-07-18 00:47:59 +0000277 }
278 return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
279}
280
kenton@google.comd37d46d2009-04-25 02:53:47 +0000281string DefaultValue(const FieldDescriptor* field) {
282 switch (field->cpp_type()) {
283 case FieldDescriptor::CPPTYPE_INT32:
jieluo@google.com4de8f552014-07-18 00:47:59 +0000284 return Int32ToString(field->default_value_int32());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000285 case FieldDescriptor::CPPTYPE_UINT32:
286 return SimpleItoa(field->default_value_uint32()) + "u";
287 case FieldDescriptor::CPPTYPE_INT64:
jieluo@google.com4de8f552014-07-18 00:47:59 +0000288 return Int64ToString(field->default_value_int64());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000289 case FieldDescriptor::CPPTYPE_UINT64:
290 return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
kenton@google.comfccb1462009-12-18 02:11:36 +0000291 case FieldDescriptor::CPPTYPE_DOUBLE: {
292 double value = field->default_value_double();
293 if (value == numeric_limits<double>::infinity()) {
294 return "::google::protobuf::internal::Infinity()";
295 } else if (value == -numeric_limits<double>::infinity()) {
296 return "-::google::protobuf::internal::Infinity()";
297 } else if (value != value) {
298 return "::google::protobuf::internal::NaN()";
299 } else {
300 return SimpleDtoa(value);
301 }
302 }
kenton@google.comd37d46d2009-04-25 02:53:47 +0000303 case FieldDescriptor::CPPTYPE_FLOAT:
kenton@google.comd2fd0632009-07-24 01:00:35 +0000304 {
kenton@google.comfccb1462009-12-18 02:11:36 +0000305 float value = field->default_value_float();
306 if (value == numeric_limits<float>::infinity()) {
307 return "static_cast<float>(::google::protobuf::internal::Infinity())";
308 } else if (value == -numeric_limits<float>::infinity()) {
309 return "static_cast<float>(-::google::protobuf::internal::Infinity())";
310 } else if (value != value) {
311 return "static_cast<float>(::google::protobuf::internal::NaN())";
312 } else {
313 string float_value = SimpleFtoa(value);
314 // If floating point value contains a period (.) or an exponent
315 // (either E or e), then append suffix 'f' to make it a float
316 // literal.
317 if (float_value.find_first_of(".eE") != string::npos) {
318 float_value.push_back('f');
319 }
320 return float_value;
kenton@google.comd2fd0632009-07-24 01:00:35 +0000321 }
kenton@google.comd2fd0632009-07-24 01:00:35 +0000322 }
kenton@google.comd37d46d2009-04-25 02:53:47 +0000323 case FieldDescriptor::CPPTYPE_BOOL:
324 return field->default_value_bool() ? "true" : "false";
325 case FieldDescriptor::CPPTYPE_ENUM:
326 // Lazy: Generate a static_cast because we don't have a helper function
327 // that constructs the full name of an enum value.
328 return strings::Substitute(
329 "static_cast< $0 >($1)",
330 ClassName(field->enum_type(), true),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000331 Int32ToString(field->default_value_enum()->number()));
kenton@google.comd37d46d2009-04-25 02:53:47 +0000332 case FieldDescriptor::CPPTYPE_STRING:
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000333 return "\"" + EscapeTrigraphs(
334 CEscape(field->default_value_string())) +
335 "\"";
kenton@google.comd37d46d2009-04-25 02:53:47 +0000336 case FieldDescriptor::CPPTYPE_MESSAGE:
kenton@google.comfccb1462009-12-18 02:11:36 +0000337 return FieldMessageTypeName(field) + "::default_instance()";
kenton@google.comd37d46d2009-04-25 02:53:47 +0000338 }
339 // Can't actually get here; make compiler happy. (We could add a default
340 // case above but then we wouldn't get the nice compiler warning when a
341 // new type is added.)
342 GOOGLE_LOG(FATAL) << "Can't get here.";
343 return "";
344}
345
temporal40ee5512008-07-10 02:12:20 +0000346// Convert a file name into a valid identifier.
347string FilenameIdentifier(const string& filename) {
348 string result;
349 for (int i = 0; i < filename.size(); i++) {
350 if (ascii_isalnum(filename[i])) {
351 result.push_back(filename[i]);
352 } else {
353 // Not alphanumeric. To avoid any possibility of name conflicts we
354 // use the hex code for the character.
Jisi Liu885b6122015-02-28 14:51:22 -0800355 StrAppend(&result, "_", ToHex(static_cast<uint8>(filename[i])));
temporal40ee5512008-07-10 02:12:20 +0000356 }
357 }
358 return result;
359}
360
kenton@google.comd37d46d2009-04-25 02:53:47 +0000361// Return the name of the AddDescriptors() function for a given file.
362string GlobalAddDescriptorsName(const string& filename) {
363 return "protobuf_AddDesc_" + FilenameIdentifier(filename);
364}
365
366// Return the name of the AssignDescriptors() function for a given file.
367string GlobalAssignDescriptorsName(const string& filename) {
368 return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
temporal40ee5512008-07-10 02:12:20 +0000369}
370
kenton@google.com63e646b2009-05-06 19:27:03 +0000371// Return the name of the ShutdownFile() function for a given file.
372string GlobalShutdownFileName(const string& filename) {
373 return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
374}
375
jieluo@google.com4de8f552014-07-18 00:47:59 +0000376// Return the qualified C++ name for a file level symbol.
377string QualifiedFileLevelSymbol(const string& package, const string& name) {
378 if (package.empty()) {
379 return StrCat("::", name);
380 }
381 return StrCat("::", DotsToColons(package), "::", name);
382}
383
liujisi@google.com5c20ca12010-12-21 05:33:13 +0000384// Escape C++ trigraphs by escaping question marks to \?
385string EscapeTrigraphs(const string& to_escape) {
386 return StringReplace(to_escape, "?", "\\?", true);
387}
388
jieluo@google.com4de8f552014-07-18 00:47:59 +0000389// Escaped function name to eliminate naming conflict.
390string SafeFunctionName(const Descriptor* descriptor,
391 const FieldDescriptor* field,
392 const string& prefix) {
393 // Do not use FieldName() since it will escape keywords.
394 string name = field->name();
395 LowerString(&name);
396 string function_name = prefix + name;
397 if (descriptor->FindFieldByName(function_name)) {
398 // Single underscore will also make it conflicting with the private data
399 // member. We use double underscore to escape function names.
400 function_name.append("__");
401 } else if (kKeywords.count(name) > 0) {
402 // If the field name is a keyword, we append the underscore back to keep it
403 // consistent with other function names.
404 function_name.append("_");
405 }
406 return function_name;
407}
408
pliard@google.com6103d4e2012-05-04 11:16:09 +0000409bool StaticInitializersForced(const FileDescriptor* file) {
410 if (HasDescriptorMethods(file) || file->extension_count() > 0) {
411 return true;
412 }
413 for (int i = 0; i < file->message_type_count(); ++i) {
414 if (HasExtension(file->message_type(i))) {
415 return true;
416 }
417 }
418 return false;
419}
420
421void PrintHandlingOptionalStaticInitializers(
422 const FileDescriptor* file, io::Printer* printer,
423 const char* with_static_init, const char* without_static_init,
424 const char* var1, const string& val1,
425 const char* var2, const string& val2) {
426 map<string, string> vars;
427 if (var1) {
428 vars[var1] = val1;
429 }
430 if (var2) {
431 vars[var2] = val2;
432 }
433 PrintHandlingOptionalStaticInitializers(
434 vars, file, printer, with_static_init, without_static_init);
435}
436
437void PrintHandlingOptionalStaticInitializers(
438 const map<string, string>& vars, const FileDescriptor* file,
439 io::Printer* printer, const char* with_static_init,
440 const char* without_static_init) {
441 if (StaticInitializersForced(file)) {
442 printer->Print(vars, with_static_init);
443 } else {
444 printer->Print(vars, (string(
445 "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") +
446 without_static_init +
447 "#else\n" +
448 with_static_init +
449 "#endif\n").c_str());
450 }
451}
452
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000453
Feng Xiaof157a562014-11-14 11:50:31 -0800454static bool HasMapFields(const Descriptor* descriptor) {
455 for (int i = 0; i < descriptor->field_count(); ++i) {
456 if (descriptor->field(i)->is_map()) {
457 return true;
458 }
459 }
460 for (int i = 0; i < descriptor->nested_type_count(); ++i) {
461 if (HasMapFields(descriptor->nested_type(i))) return true;
462 }
463 return false;
464}
465
466bool HasMapFields(const FileDescriptor* file) {
467 for (int i = 0; i < file->message_type_count(); ++i) {
468 if (HasMapFields(file->message_type(i))) return true;
469 }
470 return false;
471}
472
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000473static bool HasEnumDefinitions(const Descriptor* message_type) {
474 if (message_type->enum_type_count() > 0) return true;
475 for (int i = 0; i < message_type->nested_type_count(); ++i) {
476 if (HasEnumDefinitions(message_type->nested_type(i))) return true;
477 }
478 return false;
479}
480
481bool HasEnumDefinitions(const FileDescriptor* file) {
482 if (file->enum_type_count() > 0) return true;
483 for (int i = 0; i < file->message_type_count(); ++i) {
484 if (HasEnumDefinitions(file->message_type(i))) return true;
485 }
486 return false;
487}
488
jieluo@google.com4de8f552014-07-18 00:47:59 +0000489bool IsStringOrMessage(const FieldDescriptor* field) {
490 switch (field->cpp_type()) {
491 case FieldDescriptor::CPPTYPE_INT32:
492 case FieldDescriptor::CPPTYPE_INT64:
493 case FieldDescriptor::CPPTYPE_UINT32:
494 case FieldDescriptor::CPPTYPE_UINT64:
495 case FieldDescriptor::CPPTYPE_DOUBLE:
496 case FieldDescriptor::CPPTYPE_FLOAT:
497 case FieldDescriptor::CPPTYPE_BOOL:
498 case FieldDescriptor::CPPTYPE_ENUM:
499 return false;
500 case FieldDescriptor::CPPTYPE_STRING:
501 case FieldDescriptor::CPPTYPE_MESSAGE:
502 return true;
503 }
504
505 GOOGLE_LOG(FATAL) << "Can't get here.";
506 return false;
507}
508
Jisi Liu885b6122015-02-28 14:51:22 -0800509FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
510 GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
511 // Open-source protobuf release only supports STRING ctype.
512 return FieldOptions::STRING;
513
514}
515
temporal40ee5512008-07-10 02:12:20 +0000516} // namespace cpp
517} // namespace compiler
518} // namespace protobuf
519} // namespace google