Index: third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc |
index 990aca248c20b40221064ef82b9d2734632a19a3..196b39dd93207e5529a8e5a0701afcb72b658c2d 100644 |
--- a/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc |
+++ b/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc |
@@ -58,6 +58,14 @@ namespace protobuf { |
namespace compiler { |
namespace objectivec { |
+Options::Options() { |
+ // Default is the value of the env for the package prefixes. |
+ const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); |
+ if (file_path) { |
+ expected_prefixes_path = file_path; |
+ } |
+} |
+ |
namespace { |
hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) { |
@@ -116,9 +124,14 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) { |
} |
values.push_back(current); |
+ string result; |
+ bool first_segment_forces_upper = false; |
for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { |
string value = *i; |
bool all_upper = (kUpperSegments.count(value) > 0); |
+ if (all_upper && (result.length() == 0)) { |
+ first_segment_forces_upper = true; |
+ } |
for (int j = 0; j < value.length(); j++) { |
if (j == 0 || all_upper) { |
value[j] = ascii_toupper(value[j]); |
@@ -126,13 +139,11 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) { |
// Nothing, already in lower. |
} |
} |
- *i = value; |
+ result += value; |
} |
- string result; |
- for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { |
- result += *i; |
- } |
- if ((result.length() != 0) && !first_capitalized) { |
+ if ((result.length() != 0) && |
+ !first_capitalized && |
+ !first_segment_forces_upper) { |
result[0] = ascii_tolower(result[0]); |
} |
return result; |
@@ -209,11 +220,6 @@ string NameFromFieldDescriptor(const FieldDescriptor* field) { |
} |
} |
-// Escape C++ trigraphs by escaping question marks to \? |
-string EscapeTrigraphs(const string& to_escape) { |
- return StringReplace(to_escape, "?", "\\?", true); |
-} |
- |
void PathSplit(const string& path, string* directory, string* basename) { |
string::size_type last_slash = path.rfind('/'); |
if (last_slash == string::npos) { |
@@ -253,6 +259,11 @@ bool IsSpecialName(const string& name, const string* special_names, |
} // namespace |
+// Escape C++ trigraphs by escaping question marks to \? |
+string EscapeTrigraphs(const string& to_escape) { |
+ return StringReplace(to_escape, "?", "\\?", true); |
+} |
+ |
string StripProto(const string& filename) { |
if (HasSuffixString(filename, ".protodevel")) { |
return StripSuffixString(filename, ".protodevel"); |
@@ -723,7 +734,7 @@ string DefaultValue(const FieldDescriptor* field) { |
uint32 length = ghtonl(default_string.length()); |
string bytes((const char*)&length, sizeof(length)); |
bytes.append(default_string); |
- return "(NSData*)\"" + CEscape(bytes) + "\""; |
+ return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\""; |
} else { |
return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\""; |
} |
@@ -740,6 +751,51 @@ string DefaultValue(const FieldDescriptor* field) { |
return NULL; |
} |
+bool HasNonZeroDefaultValue(const FieldDescriptor* field) { |
+ // Repeated fields don't have defaults. |
+ if (field->is_repeated()) { |
+ return false; |
+ } |
+ |
+ // As much as checking field->has_default_value() seems useful, it isn't |
+ // because of enums. proto2 syntax allows the first item in an enum (the |
+ // default) to be non zero. So checking field->has_default_value() would |
+ // result in missing this non zero default. See MessageWithOneBasedEnum in |
+ // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. |
+ |
+ // Some proto file set the default to the zero value, so make sure the value |
+ // isn't the zero case. |
+ switch (field->cpp_type()) { |
+ case FieldDescriptor::CPPTYPE_INT32: |
+ return field->default_value_int32() != 0; |
+ case FieldDescriptor::CPPTYPE_UINT32: |
+ return field->default_value_uint32() != 0U; |
+ case FieldDescriptor::CPPTYPE_INT64: |
+ return field->default_value_int64() != 0LL; |
+ case FieldDescriptor::CPPTYPE_UINT64: |
+ return field->default_value_uint64() != 0ULL; |
+ case FieldDescriptor::CPPTYPE_DOUBLE: |
+ return field->default_value_double() != 0.0; |
+ case FieldDescriptor::CPPTYPE_FLOAT: |
+ return field->default_value_float() != 0.0f; |
+ case FieldDescriptor::CPPTYPE_BOOL: |
+ return field->default_value_bool(); |
+ case FieldDescriptor::CPPTYPE_STRING: { |
+ const string& default_string = field->default_value_string(); |
+ return default_string.length() != 0; |
+ } |
+ case FieldDescriptor::CPPTYPE_ENUM: |
+ return field->default_value_enum()->number() != 0; |
+ case FieldDescriptor::CPPTYPE_MESSAGE: |
+ return false; |
+ } |
+ |
+ // Some compilers report reaching end of function even though all cases of |
+ // the enum are handed in the switch. |
+ GOOGLE_LOG(FATAL) << "Can't get here."; |
+ return false; |
+} |
+ |
string BuildFlagsString(const vector<string>& strings) { |
if (strings.size() == 0) { |
return "0"; |
@@ -763,16 +819,14 @@ string BuildCommentsString(const SourceLocation& location) { |
while (!lines.empty() && lines.back().empty()) { |
lines.pop_back(); |
} |
- string prefix("//"); |
+ string prefix("///"); |
string suffix("\n"); |
string final_comments; |
for (int i = 0; i < lines.size(); i++) { |
- // We use $ for delimiters, so replace comments with dollars with |
- // html escaped version. |
- // None of the other compilers handle this (as of this writing) but we |
- // ran into it once, so just to be safe. |
+ // HeaderDoc uses '\' and '@' for markers; escape them. |
+ const string line = StringReplace(lines[i], "\\", "\\\\", true); |
final_comments += |
- prefix + StringReplace(lines[i], "$", "$", true) + suffix; |
+ prefix + StringReplace(line, "@", "\\@", true) + suffix; |
} |
return final_comments; |
} |
@@ -883,33 +937,33 @@ bool Parser::ParseLoop() { |
StringPiece prefix(line, offset + 1, line.length() - offset - 1); |
TrimWhitespace(&package); |
TrimWhitespace(&prefix); |
- // Don't really worry about error checking the the package/prefix for |
+ // Don't really worry about error checking the package/prefix for |
// being valid. Assume the file is validated when it is created/edited. |
(*prefix_map_)[package.ToString()] = prefix.ToString(); |
} |
return true; |
} |
-bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, |
- string* out_expect_file_path, |
+bool LoadExpectedPackagePrefixes(const Options &generation_options, |
+ map<string, string>* prefix_map, |
string* out_error) { |
- const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); |
- if (file_path == NULL) { |
+ if (generation_options.expected_prefixes_path.empty()) { |
return true; |
} |
int fd; |
do { |
- fd = open(file_path, O_RDONLY); |
+ fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY); |
} while (fd < 0 && errno == EINTR); |
if (fd < 0) { |
*out_error = |
- string(file_path) + ":0:0: error: Unable to open." + strerror(errno); |
+ string("error: Unable to open \"") + |
+ generation_options.expected_prefixes_path + |
+ "\", " + strerror(errno); |
return false; |
} |
io::FileInputStream file_stream(fd); |
file_stream.SetCloseOnDelete(true); |
- *out_expect_file_path = file_path; |
Parser parser(prefix_map); |
const void* buf; |
@@ -920,8 +974,9 @@ bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, |
} |
if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) { |
- *out_error = string(file_path) + ":" + SimpleItoa(parser.last_line()) + |
- ":0: error: " + parser.error_str(); |
+ *out_error = |
+ string("error: ") + generation_options.expected_prefixes_path + |
+ " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str(); |
return false; |
} |
} |
@@ -930,7 +985,9 @@ bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, |
} // namespace |
-bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { |
+bool ValidateObjCClassPrefix(const FileDescriptor* file, |
+ const Options& generation_options, |
+ string* out_error) { |
const string prefix = file->options().objc_class_prefix(); |
const string package = file->package(); |
@@ -939,11 +996,10 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { |
// Load any expected package prefixes to validate against those. |
map<string, string> expected_package_prefixes; |
- string expect_file_path; |
- if (!LoadExpectedPackagePrefixes(&expected_package_prefixes, |
- &expect_file_path, out_error)) { |
- // Any error, clear the entries that were read. |
- expected_package_prefixes.clear(); |
+ if (!LoadExpectedPackagePrefixes(generation_options, |
+ &expected_package_prefixes, |
+ out_error)) { |
+ return false; |
} |
// Check: Error - See if there was an expected prefix for the package and |
@@ -957,8 +1013,9 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { |
return true; |
} else { |
// ...it didn't match! |
- *out_error = "protoc:0: error: Expected 'option objc_class_prefix = \"" + |
- package_match->second + "\";' in '" + file->name() + "'"; |
+ *out_error = "error: Expected 'option objc_class_prefix = \"" + |
+ package_match->second + "\";' for package '" + package + |
+ "' in '" + file->name() + "'"; |
if (prefix.length()) { |
*out_error += "; but found '" + prefix + "' instead"; |
} |
@@ -980,11 +1037,11 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { |
i != expected_package_prefixes.end(); ++i) { |
if (i->second == prefix) { |
*out_error = |
- "protoc:0: error: Found 'option objc_class_prefix = \"" + prefix + |
+ "error: Found 'option objc_class_prefix = \"" + prefix + |
"\";' in '" + file->name() + |
"'; that prefix is already used for 'package " + i->first + |
";'. It can only be reused by listing it in the expected file (" + |
- expect_file_path + ")."; |
+ generation_options.expected_prefixes_path + ")."; |
return false; // Only report first usage of the prefix. |
} |
} |
@@ -1017,7 +1074,7 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { |
<< "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" |
<< prefix << "\";' in '" << file->name() << "';" |
<< " consider adding it to the expected prefixes file (" |
- << expect_file_path << ")." << endl; |
+ << generation_options.expected_prefixes_path << ")." << endl; |
cerr.flush(); |
} |