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 <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/logging.h>
43 : #include <google/protobuf/stubs/common.h>
44 : #include <google/protobuf/stubs/strutil.h>
45 : #include <google/protobuf/stubs/substitute.h>
46 :
47 :
48 : namespace google {
49 : namespace protobuf {
50 : namespace compiler {
51 : namespace cpp {
52 :
53 : namespace {
54 :
55 : static const char kAnyMessageName[] = "Any";
56 : static const char kAnyProtoFile[] = "google/protobuf/any.proto";
57 :
58 15080 : string DotsToUnderscores(const string& name) {
59 45240 : return StringReplace(name, ".", "_", true);
60 : }
61 :
62 2890 : string DotsToColons(const string& name) {
63 8670 : return StringReplace(name, ".", "::", true);
64 : }
65 :
66 : const char* const kKeywordList[] = {
67 : "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
68 : "bool", "break", "case", "catch", "char", "class", "compl", "const",
69 : "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
70 : "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
71 : "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
72 : "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or",
73 : "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
74 : "return", "short", "signed", "sizeof", "static", "static_assert",
75 : "static_cast", "struct", "switch", "template", "this", "thread_local",
76 : "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
77 : "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
78 : };
79 :
80 17 : hash_set<string> MakeKeywordsMap() {
81 : hash_set<string> result;
82 1394 : for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
83 4131 : result.insert(kKeywordList[i]);
84 : }
85 17 : return result;
86 : }
87 :
88 17 : hash_set<string> kKeywords = MakeKeywordsMap();
89 :
90 : // Returns whether the provided descriptor has an extension. This includes its
91 : // nested types.
92 6310 : bool HasExtension(const Descriptor* descriptor) {
93 1727 : if (descriptor->extension_count() > 0) {
94 : return true;
95 : }
96 4583 : for (int i = 0; i < descriptor->nested_type_count(); ++i) {
97 2856 : if (HasExtension(descriptor->nested_type(i))) {
98 : return true;
99 : }
100 : }
101 : return false;
102 : }
103 :
104 : } // namespace
105 :
106 5710 : string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
107 : string result;
108 : // Note: I distrust ctype.h due to locales.
109 507864 : for (int i = 0; i < input.size(); i++) {
110 496444 : if ('a' <= input[i] && input[i] <= 'z') {
111 225617 : if (cap_next_letter) {
112 18031 : result += input[i] + ('A' - 'a');
113 : } else {
114 207586 : result += input[i];
115 : }
116 : cap_next_letter = false;
117 22605 : } else if ('A' <= input[i] && input[i] <= 'Z') {
118 : // Capital letters are left as-is.
119 64 : result += input[i];
120 : cap_next_letter = false;
121 22541 : } else if ('0' <= input[i] && input[i] <= '9') {
122 8136 : result += input[i];
123 : cap_next_letter = true;
124 : } else {
125 : cap_next_letter = true;
126 : }
127 : }
128 5710 : return result;
129 : }
130 :
131 : const char kThickSeparator[] =
132 : "// ===================================================================\n";
133 : const char kThinSeparator[] =
134 : "// -------------------------------------------------------------------\n";
135 :
136 30160 : string ClassName(const Descriptor* descriptor, bool qualified) {
137 :
138 : // Find "outer", the descriptor of the top-level message in which
139 : // "descriptor" is embedded.
140 59018 : const Descriptor* outer = descriptor;
141 31504 : while (outer->containing_type() != NULL) outer = outer->containing_type();
142 :
143 15080 : const string& outer_name = outer->full_name();
144 15080 : string inner_name = descriptor->full_name().substr(outer_name.size());
145 :
146 15080 : if (qualified) {
147 10584 : return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
148 : } else {
149 37302 : return outer->name() + DotsToUnderscores(inner_name);
150 : }
151 : }
152 :
153 766 : string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
154 383 : if (enum_descriptor->containing_type() == NULL) {
155 266 : if (qualified) {
156 386 : return "::" + DotsToColons(enum_descriptor->full_name());
157 : } else {
158 73 : return enum_descriptor->name();
159 : }
160 : } else {
161 117 : string result = ClassName(enum_descriptor->containing_type(), qualified);
162 : result += '_';
163 117 : result += enum_descriptor->name();
164 117 : return result;
165 : }
166 : }
167 :
168 :
169 0 : string DependentBaseClassTemplateName(const Descriptor* descriptor) {
170 0 : return ClassName(descriptor, false) + "_InternalBase";
171 : }
172 :
173 582 : string SuperClassName(const Descriptor* descriptor) {
174 582 : return HasDescriptorMethods(descriptor->file()) ?
175 582 : "::google::protobuf::Message" : "::google::protobuf::MessageLite";
176 : }
177 :
178 0 : string DependentBaseDownCast() {
179 0 : return "reinterpret_cast<T*>(this)->";
180 : }
181 :
182 0 : string DependentBaseConstDownCast() {
183 0 : return "reinterpret_cast<const T*>(this)->";
184 : }
185 :
186 46419 : string FieldName(const FieldDescriptor* field) {
187 46419 : string result = field->name();
188 46419 : LowerString(&result);
189 46419 : if (kKeywords.count(result) > 0) {
190 272 : result.append("_");
191 : }
192 46419 : return result;
193 : }
194 :
195 337 : string EnumValueName(const EnumValueDescriptor* enum_value) {
196 337 : string result = enum_value->name();
197 337 : if (kKeywords.count(result) > 0) {
198 16 : result.append("_");
199 : }
200 337 : return result;
201 : }
202 :
203 19252 : string FieldConstantName(const FieldDescriptor *field) {
204 5068 : string field_name = UnderscoresToCamelCase(field->name(), true);
205 10136 : string result = "k" + field_name + "FieldNumber";
206 :
207 9626 : if (!field->is_extension() &&
208 : field->containing_type()->FindFieldByCamelcaseName(
209 9116 : field->camelcase_name()) != field) {
210 : // This field's camelcase name is not unique. As a hack, add the field
211 : // number to the constant name. This makes the constant rather useless,
212 : // but what can we do?
213 0 : result += "_" + SimpleItoa(field->number());
214 : }
215 :
216 5068 : return result;
217 : }
218 :
219 0 : bool IsFieldDependent(const FieldDescriptor* field) {
220 0 : if (field->containing_oneof() != NULL &&
221 0 : field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
222 : return true;
223 : }
224 0 : if (field->is_map()) {
225 0 : const Descriptor* map_descriptor = field->message_type();
226 0 : for (int i = 0; i < map_descriptor->field_count(); i++) {
227 0 : if (IsFieldDependent(map_descriptor->field(i))) {
228 : return true;
229 : }
230 : }
231 : return false;
232 : }
233 0 : if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
234 : return false;
235 : }
236 0 : if (field->containing_oneof() != NULL) {
237 : // Oneof fields will always be dependent.
238 : //
239 : // This is a unique case for field codegen. Field generators are
240 : // responsible for generating all the field-specific accessor
241 : // functions, except for the clear_*() function; instead, field
242 : // generators produce inline clearing code.
243 : //
244 : // For non-oneof fields, the Message class uses the inline clearing
245 : // code to define the field's clear_*() function, as well as in the
246 : // destructor. For oneof fields, the Message class generates a much
247 : // more complicated clear_*() function, which clears only the oneof
248 : // member that is set, in addition to clearing methods for each of the
249 : // oneof members individually.
250 : //
251 : // Since oneofs do not have their own generator class, the Message code
252 : // generation logic would be significantly complicated in order to
253 : // split dependent and non-dependent manipulation logic based on
254 : // whether the oneof truly needs to be dependent; so, for oneof fields,
255 : // we just assume it (and its constituents) should be manipulated by a
256 : // dependent base class function.
257 : //
258 : // This is less precise than how dependent message-typed fields are
259 : // handled, but the cost is limited to only the generated code for the
260 : // oneof field, which seems like an acceptable tradeoff.
261 : return true;
262 : }
263 0 : if (field->file() == field->message_type()->file()) {
264 : return false;
265 : }
266 0 : return true;
267 : }
268 :
269 0 : string DependentTypeName(const FieldDescriptor* field) {
270 0 : return "InternalBase_" + field->name() + "_T";
271 : }
272 :
273 1633 : string FieldMessageTypeName(const FieldDescriptor* field) {
274 : // Note: The Google-internal version of Protocol Buffers uses this function
275 : // as a hook point for hacks to support legacy code.
276 1633 : return ClassName(field->message_type(), true);
277 : }
278 :
279 149 : string StripProto(const string& filename) {
280 298 : if (HasSuffixString(filename, ".protodevel")) {
281 0 : return StripSuffixString(filename, ".protodevel");
282 : } else {
283 298 : return StripSuffixString(filename, ".proto");
284 : }
285 : }
286 :
287 1201 : const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
288 1201 : switch (type) {
289 : case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32";
290 171 : case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64";
291 135 : case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
292 117 : case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
293 79 : case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
294 59 : case FieldDescriptor::CPPTYPE_FLOAT : return "float";
295 73 : case FieldDescriptor::CPPTYPE_BOOL : return "bool";
296 0 : case FieldDescriptor::CPPTYPE_ENUM : return "int";
297 48 : case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
298 0 : case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
299 :
300 : // No default because we want the compiler to complain if any new
301 : // CppTypes are added.
302 : }
303 :
304 0 : GOOGLE_LOG(FATAL) << "Can't get here.";
305 0 : return NULL;
306 : }
307 :
308 9770 : const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
309 9770 : switch (type) {
310 : case FieldDescriptor::TYPE_INT32 : return "Int32";
311 163 : case FieldDescriptor::TYPE_INT64 : return "Int64";
312 211 : case FieldDescriptor::TYPE_UINT32 : return "UInt32";
313 143 : case FieldDescriptor::TYPE_UINT64 : return "UInt64";
314 108 : case FieldDescriptor::TYPE_SINT32 : return "SInt32";
315 104 : case FieldDescriptor::TYPE_SINT64 : return "SInt64";
316 112 : case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
317 108 : case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
318 104 : case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
319 104 : case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
320 157 : case FieldDescriptor::TYPE_FLOAT : return "Float";
321 246 : case FieldDescriptor::TYPE_DOUBLE : return "Double";
322 :
323 174 : case FieldDescriptor::TYPE_BOOL : return "Bool";
324 370 : case FieldDescriptor::TYPE_ENUM : return "Enum";
325 :
326 4613 : case FieldDescriptor::TYPE_STRING : return "String";
327 142 : case FieldDescriptor::TYPE_BYTES : return "Bytes";
328 88 : case FieldDescriptor::TYPE_GROUP : return "Group";
329 1889 : case FieldDescriptor::TYPE_MESSAGE : return "Message";
330 :
331 : // No default because we want the compiler to complain if any new
332 : // types are added.
333 : }
334 0 : GOOGLE_LOG(FATAL) << "Can't get here.";
335 0 : return "";
336 : }
337 :
338 778 : string Int32ToString(int number) {
339 : // gcc rejects the decimal form of kint32min.
340 778 : if (number == kint32min) {
341 : GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
342 1 : return "(~0x7fffffff)";
343 : } else {
344 777 : return SimpleItoa(number);
345 : }
346 : }
347 :
348 133 : string Int64ToString(int64 number) {
349 : // gcc rejects the decimal form of kint64min
350 133 : if (number == kint64min) {
351 : // Make sure we are in a 2's complement system.
352 : GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff),
353 : kint64min_value_error);
354 1 : return "GOOGLE_LONGLONG(~0x7fffffffffffffff)";
355 : }
356 396 : return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
357 : }
358 :
359 4329 : string DefaultValue(const FieldDescriptor* field) {
360 4358 : switch (field->cpp_type()) {
361 : case FieldDescriptor::CPPTYPE_INT32:
362 360 : return Int32ToString(field->default_value_int32());
363 : case FieldDescriptor::CPPTYPE_UINT32:
364 218 : return SimpleItoa(field->default_value_uint32()) + "u";
365 : case FieldDescriptor::CPPTYPE_INT64:
366 133 : return Int64ToString(field->default_value_int64());
367 : case FieldDescriptor::CPPTYPE_UINT64:
368 273 : return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
369 : case FieldDescriptor::CPPTYPE_DOUBLE: {
370 73 : double value = field->default_value_double();
371 73 : if (value == numeric_limits<double>::infinity()) {
372 1 : return "::google::protobuf::internal::Infinity()";
373 72 : } else if (value == -numeric_limits<double>::infinity()) {
374 1 : return "-::google::protobuf::internal::Infinity()";
375 71 : } else if (value != value) {
376 1 : return "::google::protobuf::internal::NaN()";
377 : } else {
378 70 : return SimpleDtoa(value);
379 : }
380 : }
381 : case FieldDescriptor::CPPTYPE_FLOAT:
382 : {
383 51 : float value = field->default_value_float();
384 51 : if (value == numeric_limits<float>::infinity()) {
385 1 : return "static_cast<float>(::google::protobuf::internal::Infinity())";
386 50 : } else if (value == -numeric_limits<float>::infinity()) {
387 1 : return "static_cast<float>(-::google::protobuf::internal::Infinity())";
388 49 : } else if (value != value) {
389 1 : return "static_cast<float>(::google::protobuf::internal::NaN())";
390 : } else {
391 48 : string float_value = SimpleFtoa(value);
392 : // If floating point value contains a period (.) or an exponent
393 : // (either E or e), then append suffix 'f' to make it a float
394 : // literal.
395 48 : if (float_value.find_first_of(".eE") != string::npos) {
396 9 : float_value.push_back('f');
397 : }
398 48 : return float_value;
399 : }
400 : }
401 : case FieldDescriptor::CPPTYPE_BOOL:
402 57 : return field->default_value_bool() ? "true" : "false";
403 : case FieldDescriptor::CPPTYPE_ENUM:
404 : // Lazy: Generate a static_cast because we don't have a helper function
405 : // that constructs the full name of an enum value.
406 : return strings::Substitute(
407 : "static_cast< $0 >($1)",
408 : ClassName(field->enum_type(), true),
409 115 : Int32ToString(field->default_value_enum()->number()));
410 : case FieldDescriptor::CPPTYPE_STRING:
411 4920 : return "\"" + EscapeTrigraphs(
412 1230 : CEscape(field->default_value_string())) +
413 1230 : "\"";
414 : case FieldDescriptor::CPPTYPE_MESSAGE:
415 104 : return FieldMessageTypeName(field) + "::default_instance()";
416 : }
417 : // Can't actually get here; make compiler happy. (We could add a default
418 : // case above but then we wouldn't get the nice compiler warning when a
419 : // new type is added.)
420 0 : GOOGLE_LOG(FATAL) << "Can't get here.";
421 0 : return "";
422 : }
423 :
424 : // Convert a file name into a valid identifier.
425 2044 : string FilenameIdentifier(const string& filename) {
426 : string result;
427 168610 : for (int i = 0; i < filename.size(); i++) {
428 246783 : if (ascii_isalnum(filename[i])) {
429 72318 : result.push_back(filename[i]);
430 : } else {
431 : // Not alphanumeric. To avoid any possibility of name conflicts we
432 : // use the hex code for the character.
433 29829 : StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
434 : }
435 : }
436 2044 : return result;
437 : }
438 :
439 : // Return the name of the AddDescriptors() function for a given file.
440 1082 : string GlobalAddDescriptorsName(const string& filename) {
441 2164 : return "protobuf_AddDesc_" + FilenameIdentifier(filename);
442 : }
443 :
444 : // Return the name of the AssignDescriptors() function for a given file.
445 426 : string GlobalAssignDescriptorsName(const string& filename) {
446 852 : return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
447 : }
448 :
449 : // Return the name of the ShutdownFile() function for a given file.
450 438 : string GlobalShutdownFileName(const string& filename) {
451 876 : return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
452 : }
453 :
454 : // Return the qualified C++ name for a file level symbol.
455 51 : string QualifiedFileLevelSymbol(const string& package, const string& name) {
456 51 : if (package.empty()) {
457 0 : return StrCat("::", name);
458 : }
459 153 : return StrCat("::", DotsToColons(package), "::", name);
460 : }
461 :
462 : // Escape C++ trigraphs by escaping question marks to \?
463 8888 : string EscapeTrigraphs(const string& to_escape) {
464 26664 : return StringReplace(to_escape, "?", "\\?", true);
465 : }
466 :
467 : // Escaped function name to eliminate naming conflict.
468 1578 : string SafeFunctionName(const Descriptor* descriptor,
469 1578 : const FieldDescriptor* field,
470 : const string& prefix) {
471 : // Do not use FieldName() since it will escape keywords.
472 1578 : string name = field->name();
473 1578 : LowerString(&name);
474 1578 : string function_name = prefix + name;
475 1578 : if (descriptor->FindFieldByName(function_name)) {
476 : // Single underscore will also make it conflicting with the private data
477 : // member. We use double underscore to escape function names.
478 2 : function_name.append("__");
479 1576 : } else if (kKeywords.count(name) > 0) {
480 : // If the field name is a keyword, we append the underscore back to keep it
481 : // consistent with other function names.
482 3 : function_name.append("_");
483 : }
484 1578 : return function_name;
485 : }
486 :
487 2795 : bool StaticInitializersForced(const FileDescriptor* file) {
488 2136 : if (HasDescriptorMethods(file) || file->extension_count() > 0) {
489 : return true;
490 : }
491 659 : for (int i = 0; i < file->message_type_count(); ++i) {
492 598 : if (HasExtension(file->message_type(i))) {
493 : return true;
494 : }
495 : }
496 : return false;
497 : }
498 :
499 1241 : void PrintHandlingOptionalStaticInitializers(
500 : const FileDescriptor* file, io::Printer* printer,
501 : const char* with_static_init, const char* without_static_init,
502 : const char* var1, const string& val1,
503 : const char* var2, const string& val2) {
504 : map<string, string> vars;
505 1241 : if (var1) {
506 1868 : vars[var1] = val1;
507 : }
508 1241 : if (var2) {
509 1184 : vars[var2] = val2;
510 : }
511 : PrintHandlingOptionalStaticInitializers(
512 1241 : vars, file, printer, with_static_init, without_static_init);
513 1241 : }
514 :
515 1659 : void PrintHandlingOptionalStaticInitializers(
516 : const map<string, string>& vars, const FileDescriptor* file,
517 : io::Printer* printer, const char* with_static_init,
518 : const char* without_static_init) {
519 1659 : if (StaticInitializersForced(file)) {
520 1610 : printer->Print(vars, with_static_init);
521 : } else {
522 : printer->Print(vars, (string(
523 147 : "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") +
524 98 : without_static_init +
525 98 : "#else\n" +
526 98 : with_static_init +
527 49 : "#endif\n").c_str());
528 : }
529 1659 : }
530 :
531 :
532 5088 : static bool HasMapFields(const Descriptor* descriptor) {
533 4734 : for (int i = 0; i < descriptor->field_count(); ++i) {
534 4232 : if (descriptor->field(i)->is_map()) {
535 : return true;
536 : }
537 : }
538 347 : for (int i = 0; i < descriptor->nested_type_count(); ++i) {
539 96 : if (HasMapFields(descriptor->nested_type(i))) return true;
540 : }
541 : return false;
542 : }
543 :
544 511 : bool HasMapFields(const FileDescriptor* file) {
545 504 : for (int i = 0; i < file->message_type_count(); ++i) {
546 420 : if (HasMapFields(file->message_type(i))) return true;
547 : }
548 : return false;
549 : }
550 :
551 502 : static bool HasEnumDefinitions(const Descriptor* message_type) {
552 196 : if (message_type->enum_type_count() > 0) return true;
553 306 : for (int i = 0; i < message_type->nested_type_count(); ++i) {
554 116 : if (HasEnumDefinitions(message_type->nested_type(i))) return true;
555 : }
556 : return false;
557 : }
558 :
559 430 : bool HasEnumDefinitions(const FileDescriptor* file) {
560 98 : if (file->enum_type_count() > 0) return true;
561 326 : for (int i = 0; i < file->message_type_count(); ++i) {
562 276 : if (HasEnumDefinitions(file->message_type(i))) return true;
563 : }
564 : return false;
565 : }
566 :
567 91 : bool IsStringOrMessage(const FieldDescriptor* field) {
568 182 : switch (field->cpp_type()) {
569 : case FieldDescriptor::CPPTYPE_INT32:
570 : case FieldDescriptor::CPPTYPE_INT64:
571 : case FieldDescriptor::CPPTYPE_UINT32:
572 : case FieldDescriptor::CPPTYPE_UINT64:
573 : case FieldDescriptor::CPPTYPE_DOUBLE:
574 : case FieldDescriptor::CPPTYPE_FLOAT:
575 : case FieldDescriptor::CPPTYPE_BOOL:
576 : case FieldDescriptor::CPPTYPE_ENUM:
577 : return false;
578 : case FieldDescriptor::CPPTYPE_STRING:
579 : case FieldDescriptor::CPPTYPE_MESSAGE:
580 68 : return true;
581 : }
582 :
583 0 : GOOGLE_LOG(FATAL) << "Can't get here.";
584 0 : return false;
585 : }
586 :
587 1192 : FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
588 : GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
589 : // Open-source protobuf release only supports STRING ctype.
590 1192 : return FieldOptions::STRING;
591 :
592 : }
593 :
594 49 : bool IsAnyMessage(const FileDescriptor* descriptor) {
595 98 : return descriptor->name() == kAnyProtoFile;
596 : }
597 :
598 1746 : bool IsAnyMessage(const Descriptor* descriptor) {
599 3492 : return descriptor->name() == kAnyMessageName &&
600 1746 : descriptor->file()->name() == kAnyProtoFile;
601 : }
602 :
603 : enum Utf8CheckMode {
604 : STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields.
605 : VERIFY = 1, // Only log an error but parsing will succeed.
606 : NONE = 2, // No UTF-8 check.
607 : };
608 :
609 : // Which level of UTF-8 enforcemant is placed on this file.
610 463 : static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) {
611 463 : if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
612 : return STRICT;
613 506 : } else if (field->file()->options().optimize_for() !=
614 : FileOptions::LITE_RUNTIME) {
615 : return VERIFY;
616 : } else {
617 : return NONE;
618 : }
619 : }
620 :
621 898 : static void GenerateUtf8CheckCode(const FieldDescriptor* field,
622 : bool for_parse,
623 : const map<string, string>& variables,
624 : const char* parameters,
625 : const char* strict_function,
626 : const char* verify_function,
627 : io::Printer* printer) {
628 463 : switch (GetUtf8CheckMode(field)) {
629 : case STRICT: {
630 210 : if (for_parse) {
631 70 : printer->Print("DO_(");
632 : }
633 : printer->Print(
634 : "::google::protobuf::internal::WireFormatLite::$function$(\n",
635 420 : "function", strict_function);
636 210 : printer->Indent();
637 210 : printer->Print(variables, parameters);
638 210 : if (for_parse) {
639 70 : printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n");
640 : } else {
641 140 : printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n");
642 : }
643 210 : printer->Print("\"$full_name$\")", "full_name", field->full_name());
644 210 : if (for_parse) {
645 70 : printer->Print(")");
646 : }
647 210 : printer->Print(";\n");
648 210 : printer->Outdent();
649 210 : break;
650 : }
651 : case VERIFY: {
652 : printer->Print(
653 : "::google::protobuf::internal::WireFormat::$function$(\n",
654 450 : "function", verify_function);
655 225 : printer->Indent();
656 225 : printer->Print(variables, parameters);
657 225 : if (for_parse) {
658 75 : printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n");
659 : } else {
660 150 : printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n");
661 : }
662 225 : printer->Print("\"$full_name$\");\n", "full_name", field->full_name());
663 225 : printer->Outdent();
664 225 : break;
665 : }
666 : case NONE:
667 : break;
668 : }
669 463 : }
670 :
671 463 : void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
672 : bool for_parse,
673 : const map<string, string>& variables,
674 : const char* parameters,
675 : io::Printer* printer) {
676 : GenerateUtf8CheckCode(field, for_parse, variables, parameters,
677 : "VerifyUtf8String", "VerifyUTF8StringNamedField",
678 463 : printer);
679 463 : }
680 :
681 0 : void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
682 : bool for_parse,
683 : const map<string, string>& variables,
684 : const char* parameters,
685 : io::Printer* printer) {
686 : GenerateUtf8CheckCode(field, for_parse, variables, parameters,
687 : "VerifyUtf8Cord", "VerifyUTF8CordNamedField",
688 0 : printer);
689 0 : }
690 :
691 : } // namespace cpp
692 : } // namespace compiler
693 : } // namespace protobuf
694 51 : } // namespace google
|