Index: third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc |
index c53d5d3e22573470deac7e19f5c44fea75aa41af..fb46e3879104eb1c831636cfcdacdac322e256d6 100644 |
--- a/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc |
+++ b/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc |
@@ -1,6 +1,6 @@ |
// Protocol Buffers - Google's data interchange format |
// Copyright 2008 Google Inc. All rights reserved. |
-// http://code.google.com/p/protobuf/ |
+// https://developers.google.com/protocol-buffers/ |
// |
// Redistribution and use in source and binary forms, with or without |
// modification, are permitted provided that the following conditions are |
@@ -39,6 +39,7 @@ |
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
#include <google/protobuf/io/printer.h> |
+#include <google/protobuf/stubs/logging.h> |
#include <google/protobuf/stubs/common.h> |
#include <google/protobuf/stubs/strutil.h> |
#include <google/protobuf/stubs/substitute.h> |
@@ -51,6 +52,10 @@ namespace cpp { |
namespace { |
+static const char kAnyMessageName[] = "Any"; |
+static const char kAnyProtoFile[] = "google/protobuf/any.proto"; |
+static const char kGoogleProtobufPrefix[] = "google/protobuf/"; |
+ |
string DotsToUnderscores(const string& name) { |
return StringReplace(name, ".", "_", true); |
} |
@@ -60,16 +65,17 @@ string DotsToColons(const string& name) { |
} |
const char* const kKeywordList[] = { |
- "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", |
- "catch", "char", "class", "compl", "const", "const_cast", "continue", |
- "default", "delete", "do", "double", "dynamic_cast", "else", "enum", |
- "explicit", "extern", "false", "float", "for", "friend", "goto", "if", |
- "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq", |
- "operator", "or", "or_eq", "private", "protected", "public", "register", |
- "reinterpret_cast", "return", "short", "signed", "sizeof", "static", |
- "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", |
- "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", |
- "void", "volatile", "wchar_t", "while", "xor", "xor_eq" |
+ "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", |
+ "bool", "break", "case", "catch", "char", "class", "compl", "const", |
+ "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", |
+ "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false", |
+ "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", |
+ "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or", |
+ "or_eq", "private", "protected", "public", "register", "reinterpret_cast", |
+ "return", "short", "signed", "sizeof", "static", "static_assert", |
+ "static_cast", "struct", "switch", "template", "this", "thread_local", |
+ "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", |
+ "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" |
}; |
hash_set<string> MakeKeywordsMap() { |
@@ -82,6 +88,22 @@ hash_set<string> MakeKeywordsMap() { |
hash_set<string> kKeywords = MakeKeywordsMap(); |
+// Returns whether the provided descriptor has an extension. This includes its |
+// nested types. |
+bool HasExtension(const Descriptor* descriptor) { |
+ if (descriptor->extension_count() > 0) { |
+ return true; |
+ } |
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) { |
+ if (HasExtension(descriptor->nested_type(i))) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+} // namespace |
+ |
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { |
string result; |
// Note: I distrust ctype.h due to locales. |
@@ -107,22 +129,6 @@ string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { |
return result; |
} |
-// Returns whether the provided descriptor has an extension. This includes its |
-// nested types. |
-bool HasExtension(const Descriptor* descriptor) { |
- if (descriptor->extension_count() > 0) { |
- return true; |
- } |
- for (int i = 0; i < descriptor->nested_type_count(); ++i) { |
- if (HasExtension(descriptor->nested_type(i))) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-} // namespace |
- |
const char kThickSeparator[] = |
"// ===================================================================\n"; |
const char kThinSeparator[] = |
@@ -161,11 +167,23 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { |
} |
+string DependentBaseClassTemplateName(const Descriptor* descriptor) { |
+ return ClassName(descriptor, false) + "_InternalBase"; |
+} |
+ |
string SuperClassName(const Descriptor* descriptor) { |
return HasDescriptorMethods(descriptor->file()) ? |
"::google::protobuf::Message" : "::google::protobuf::MessageLite"; |
} |
+string DependentBaseDownCast() { |
+ return "reinterpret_cast<T*>(this)->"; |
+} |
+ |
+string DependentBaseConstDownCast() { |
+ return "reinterpret_cast<const T*>(this)->"; |
+} |
+ |
string FieldName(const FieldDescriptor* field) { |
string result = field->name(); |
LowerString(&result); |
@@ -175,6 +193,14 @@ string FieldName(const FieldDescriptor* field) { |
return result; |
} |
+string EnumValueName(const EnumValueDescriptor* enum_value) { |
+ string result = enum_value->name(); |
+ if (kKeywords.count(result) > 0) { |
+ result.append("_"); |
+ } |
+ return result; |
+} |
+ |
string FieldConstantName(const FieldDescriptor *field) { |
string field_name = UnderscoresToCamelCase(field->name(), true); |
string result = "k" + field_name + "FieldNumber"; |
@@ -191,6 +217,60 @@ string FieldConstantName(const FieldDescriptor *field) { |
return result; |
} |
+bool IsFieldDependent(const FieldDescriptor* field) { |
+ if (field->containing_oneof() != NULL && |
+ field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { |
+ return true; |
+ } |
+ if (field->is_map()) { |
+ const Descriptor* map_descriptor = field->message_type(); |
+ for (int i = 0; i < map_descriptor->field_count(); i++) { |
+ if (IsFieldDependent(map_descriptor->field(i))) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { |
+ return false; |
+ } |
+ if (field->containing_oneof() != NULL) { |
+ // Oneof fields will always be dependent. |
+ // |
+ // This is a unique case for field codegen. Field generators are |
+ // responsible for generating all the field-specific accessor |
+ // functions, except for the clear_*() function; instead, field |
+ // generators produce inline clearing code. |
+ // |
+ // For non-oneof fields, the Message class uses the inline clearing |
+ // code to define the field's clear_*() function, as well as in the |
+ // destructor. For oneof fields, the Message class generates a much |
+ // more complicated clear_*() function, which clears only the oneof |
+ // member that is set, in addition to clearing methods for each of the |
+ // oneof members individually. |
+ // |
+ // Since oneofs do not have their own generator class, the Message code |
+ // generation logic would be significantly complicated in order to |
+ // split dependent and non-dependent manipulation logic based on |
+ // whether the oneof truly needs to be dependent; so, for oneof fields, |
+ // we just assume it (and its constituents) should be manipulated by a |
+ // dependent base class function. |
+ // |
+ // This is less precise than how dependent message-typed fields are |
+ // handled, but the cost is limited to only the generated code for the |
+ // oneof field, which seems like an acceptable tradeoff. |
+ return true; |
+ } |
+ if (field->file() == field->message_type()->file()) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+string DependentTypeName(const FieldDescriptor* field) { |
+ return "InternalBase_" + field->name() + "_T"; |
+} |
+ |
string FieldMessageTypeName(const FieldDescriptor* field) { |
// Note: The Google-internal version of Protocol Buffers uses this function |
// as a hook point for hacks to support legacy code. |
@@ -256,31 +336,35 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { |
return ""; |
} |
+string Int32ToString(int number) { |
+ // gcc rejects the decimal form of kint32min. |
+ if (number == kint32min) { |
+ GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error); |
+ return "(~0x7fffffff)"; |
+ } else { |
+ return SimpleItoa(number); |
+ } |
+} |
+ |
+string Int64ToString(int64 number) { |
+ // gcc rejects the decimal form of kint64min |
+ if (number == kint64min) { |
+ // Make sure we are in a 2's complement system. |
+ GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff), |
+ kint64min_value_error); |
+ return "GOOGLE_LONGLONG(~0x7fffffffffffffff)"; |
+ } |
+ return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")"; |
+} |
+ |
string DefaultValue(const FieldDescriptor* field) { |
switch (field->cpp_type()) { |
case FieldDescriptor::CPPTYPE_INT32: |
- // gcc rejects the decimal form of kint32min and kint64min. |
- if (field->default_value_int32() == kint32min) { |
- // Make sure we are in a 2's complement system. |
- GOOGLE_COMPILE_ASSERT( |
- (uint32)kint32min == (uint32)0 - (uint32)0x80000000, |
- kint32min_value_error); |
- return "-0x80000000"; |
- } |
- return SimpleItoa(field->default_value_int32()); |
+ return Int32ToString(field->default_value_int32()); |
case FieldDescriptor::CPPTYPE_UINT32: |
return SimpleItoa(field->default_value_uint32()) + "u"; |
case FieldDescriptor::CPPTYPE_INT64: |
- // See the comments for CPPTYPE_INT32. |
- if (field->default_value_int64() == kint64min) { |
- // Make sure we are in a 2's complement system. |
- GOOGLE_COMPILE_ASSERT( |
- (uint64)kint64min == |
- (uint64)0 - (uint64)GOOGLE_LONGLONG(0x8000000000000000), |
- kint64min_value_error); |
- return "GOOGLE_LONGLONG(-0x8000000000000000)"; |
- } |
- return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; |
+ return Int64ToString(field->default_value_int64()); |
case FieldDescriptor::CPPTYPE_UINT64: |
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; |
case FieldDescriptor::CPPTYPE_DOUBLE: { |
@@ -323,7 +407,7 @@ string DefaultValue(const FieldDescriptor* field) { |
return strings::Substitute( |
"static_cast< $0 >($1)", |
ClassName(field->enum_type(), true), |
- field->default_value_enum()->number()); |
+ Int32ToString(field->default_value_enum()->number())); |
case FieldDescriptor::CPPTYPE_STRING: |
return "\"" + EscapeTrigraphs( |
CEscape(field->default_value_string())) + |
@@ -347,9 +431,7 @@ string FilenameIdentifier(const string& filename) { |
} else { |
// Not alphanumeric. To avoid any possibility of name conflicts we |
// use the hex code for the character. |
- result.push_back('_'); |
- char buffer[kFastToBufferSize]; |
- result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer)); |
+ StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i]))); |
} |
} |
return result; |
@@ -370,11 +452,39 @@ string GlobalShutdownFileName(const string& filename) { |
return "protobuf_ShutdownFile_" + FilenameIdentifier(filename); |
} |
+// Return the qualified C++ name for a file level symbol. |
+string QualifiedFileLevelSymbol(const string& package, const string& name) { |
+ if (package.empty()) { |
+ return StrCat("::", name); |
+ } |
+ return StrCat("::", DotsToColons(package), "::", name); |
+} |
+ |
// Escape C++ trigraphs by escaping question marks to \? |
string EscapeTrigraphs(const string& to_escape) { |
return StringReplace(to_escape, "?", "\\?", true); |
} |
+// Escaped function name to eliminate naming conflict. |
+string SafeFunctionName(const Descriptor* descriptor, |
+ const FieldDescriptor* field, |
+ const string& prefix) { |
+ // Do not use FieldName() since it will escape keywords. |
+ string name = field->name(); |
+ LowerString(&name); |
+ string function_name = prefix + name; |
+ if (descriptor->FindFieldByName(function_name)) { |
+ // Single underscore will also make it conflicting with the private data |
+ // member. We use double underscore to escape function names. |
+ function_name.append("__"); |
+ } else if (kKeywords.count(name) > 0) { |
+ // If the field name is a keyword, we append the underscore back to keep it |
+ // consistent with other function names. |
+ function_name.append("_"); |
+ } |
+ return function_name; |
+} |
+ |
bool StaticInitializersForced(const FileDescriptor* file) { |
if (HasDescriptorMethods(file) || file->extension_count() > 0) { |
return true; |
@@ -420,6 +530,25 @@ void PrintHandlingOptionalStaticInitializers( |
} |
+static bool HasMapFields(const Descriptor* descriptor) { |
+ for (int i = 0; i < descriptor->field_count(); ++i) { |
+ if (descriptor->field(i)->is_map()) { |
+ return true; |
+ } |
+ } |
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) { |
+ if (HasMapFields(descriptor->nested_type(i))) return true; |
+ } |
+ return false; |
+} |
+ |
+bool HasMapFields(const FileDescriptor* file) { |
+ for (int i = 0; i < file->message_type_count(); ++i) { |
+ if (HasMapFields(file->message_type(i))) return true; |
+ } |
+ return false; |
+} |
+ |
static bool HasEnumDefinitions(const Descriptor* message_type) { |
if (message_type->enum_type_count() > 0) return true; |
for (int i = 0; i < message_type->nested_type_count(); ++i) { |
@@ -436,6 +565,134 @@ bool HasEnumDefinitions(const FileDescriptor* file) { |
return false; |
} |
+bool IsStringOrMessage(const FieldDescriptor* field) { |
+ switch (field->cpp_type()) { |
+ case FieldDescriptor::CPPTYPE_INT32: |
+ case FieldDescriptor::CPPTYPE_INT64: |
+ case FieldDescriptor::CPPTYPE_UINT32: |
+ case FieldDescriptor::CPPTYPE_UINT64: |
+ case FieldDescriptor::CPPTYPE_DOUBLE: |
+ case FieldDescriptor::CPPTYPE_FLOAT: |
+ case FieldDescriptor::CPPTYPE_BOOL: |
+ case FieldDescriptor::CPPTYPE_ENUM: |
+ return false; |
+ case FieldDescriptor::CPPTYPE_STRING: |
+ case FieldDescriptor::CPPTYPE_MESSAGE: |
+ return true; |
+ } |
+ |
+ GOOGLE_LOG(FATAL) << "Can't get here."; |
+ return false; |
+} |
+ |
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) { |
+ GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); |
+ // Open-source protobuf release only supports STRING ctype. |
+ return FieldOptions::STRING; |
+ |
+} |
+ |
+bool IsAnyMessage(const FileDescriptor* descriptor) { |
+ return descriptor->name() == kAnyProtoFile; |
+} |
+ |
+bool IsAnyMessage(const Descriptor* descriptor) { |
+ return descriptor->name() == kAnyMessageName && |
+ descriptor->file()->name() == kAnyProtoFile; |
+} |
+ |
+bool IsWellKnownMessage(const FileDescriptor* descriptor) { |
+ return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix); |
+} |
+ |
+enum Utf8CheckMode { |
+ STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields. |
+ VERIFY = 1, // Only log an error but parsing will succeed. |
+ NONE = 2, // No UTF-8 check. |
+}; |
+ |
+// Which level of UTF-8 enforcemant is placed on this file. |
+static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) { |
+ if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { |
+ return STRICT; |
+ } else if (field->file()->options().optimize_for() != |
+ FileOptions::LITE_RUNTIME) { |
+ return VERIFY; |
+ } else { |
+ return NONE; |
+ } |
+} |
+ |
+static void GenerateUtf8CheckCode(const FieldDescriptor* field, |
+ bool for_parse, |
+ const map<string, string>& variables, |
+ const char* parameters, |
+ const char* strict_function, |
+ const char* verify_function, |
+ io::Printer* printer) { |
+ switch (GetUtf8CheckMode(field)) { |
+ case STRICT: { |
+ if (for_parse) { |
+ printer->Print("DO_("); |
+ } |
+ printer->Print( |
+ "::google::protobuf::internal::WireFormatLite::$function$(\n", |
+ "function", strict_function); |
+ printer->Indent(); |
+ printer->Print(variables, parameters); |
+ if (for_parse) { |
+ printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n"); |
+ } else { |
+ printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n"); |
+ } |
+ printer->Print("\"$full_name$\")", "full_name", field->full_name()); |
+ if (for_parse) { |
+ printer->Print(")"); |
+ } |
+ printer->Print(";\n"); |
+ printer->Outdent(); |
+ break; |
+ } |
+ case VERIFY: { |
+ printer->Print( |
+ "::google::protobuf::internal::WireFormat::$function$(\n", |
+ "function", verify_function); |
+ printer->Indent(); |
+ printer->Print(variables, parameters); |
+ if (for_parse) { |
+ printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n"); |
+ } else { |
+ printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n"); |
+ } |
+ printer->Print("\"$full_name$\");\n", "full_name", field->full_name()); |
+ printer->Outdent(); |
+ break; |
+ } |
+ case NONE: |
+ break; |
+ } |
+} |
+ |
+void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, |
+ bool for_parse, |
+ const map<string, string>& variables, |
+ const char* parameters, |
+ io::Printer* printer) { |
+ GenerateUtf8CheckCode(field, for_parse, variables, parameters, |
+ "VerifyUtf8String", "VerifyUTF8StringNamedField", |
+ printer); |
+} |
+ |
+void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, |
+ bool for_parse, |
+ const map<string, string>& variables, |
+ const char* parameters, |
+ io::Printer* printer) { |
+ GenerateUtf8CheckCode(field, for_parse, variables, parameters, |
+ "VerifyUtf8Cord", "VerifyUTF8CordNamedField", |
+ printer); |
+} |
+ |
} // namespace cpp |
} // namespace compiler |
} // namespace protobuf |