| Index: third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_helpers.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_helpers.cc
|
| index c51fe44b391ec1cd4f8de654a9bdefb653d8a75c..6c154c5a5862950d110f2d5049f6ca1af0e2b52a 100644
|
| --- a/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_helpers.cc
|
| +++ b/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_helpers.cc
|
| @@ -48,6 +48,7 @@
|
| #include <google/protobuf/compiler/csharp/csharp_enum_field.h>
|
| #include <google/protobuf/compiler/csharp/csharp_map_field.h>
|
| #include <google/protobuf/compiler/csharp/csharp_message_field.h>
|
| +#include <google/protobuf/compiler/csharp/csharp_options.h>
|
| #include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
|
| #include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
|
| #include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
|
| @@ -127,7 +128,8 @@ std::string GetFileNameBase(const FileDescriptor* descriptor) {
|
| }
|
|
|
| std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
|
| - // TODO: Detect collisions with existing messages, and append an underscore if necessary.
|
| + // TODO: Detect collisions with existing messages,
|
| + // and append an underscore if necessary.
|
| return GetFileNameBase(descriptor) + "Reflection";
|
| }
|
|
|
| @@ -176,6 +178,104 @@ std::string UnderscoresToPascalCase(const std::string& input) {
|
| return UnderscoresToCamelCase(input, true);
|
| }
|
|
|
| +// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty)
|
| +// into a PascalCase string. Precise rules implemented:
|
| +
|
| +// Previous input character Current character Case
|
| +// Any Non-alphanumeric Skipped
|
| +// None - first char of input Alphanumeric Upper
|
| +// Non-letter (e.g. _ or 1) Alphanumeric Upper
|
| +// Numeric Alphanumeric Upper
|
| +// Lower letter Alphanumeric Same as current
|
| +// Upper letter Alphanumeric Lower
|
| +std::string ShoutyToPascalCase(const std::string& input) {
|
| + string result;
|
| + // Simple way of implementing "always start with upper"
|
| + char previous = '_';
|
| + for (int i = 0; i < input.size(); i++) {
|
| + char current = input[i];
|
| + if (!ascii_isalnum(current)) {
|
| + previous = current;
|
| + continue;
|
| + }
|
| + if (!ascii_isalnum(previous)) {
|
| + result += ascii_toupper(current);
|
| + } else if (ascii_isdigit(previous)) {
|
| + result += ascii_toupper(current);
|
| + } else if (ascii_islower(previous)) {
|
| + result += current;
|
| + } else {
|
| + result += ascii_tolower(current);
|
| + }
|
| + previous = current;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +// Attempt to remove a prefix from a value, ignoring casing and skipping underscores.
|
| +// (foo, foo_bar) => bar - underscore after prefix is skipped
|
| +// (FOO, foo_bar) => bar - casing is ignored
|
| +// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored
|
| +// (foobar, foo_barbaz) => baz - underscore in value is ignored
|
| +// (foo, bar) => bar - prefix isn't matched; return original value
|
| +std::string TryRemovePrefix(const std::string& prefix, const std::string& value) {
|
| + // First normalize to a lower-case no-underscores prefix to match against
|
| + std::string prefix_to_match = "";
|
| + for (size_t i = 0; i < prefix.size(); i++) {
|
| + if (prefix[i] != '_') {
|
| + prefix_to_match += ascii_tolower(prefix[i]);
|
| + }
|
| + }
|
| +
|
| + // This keeps track of how much of value we've consumed
|
| + size_t prefix_index, value_index;
|
| + for (prefix_index = 0, value_index = 0;
|
| + prefix_index < prefix_to_match.size() && value_index < value.size();
|
| + value_index++) {
|
| + // Skip over underscores in the value
|
| + if (value[value_index] == '_') {
|
| + continue;
|
| + }
|
| + if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) {
|
| + // Failed to match the prefix - bail out early.
|
| + return value;
|
| + }
|
| + }
|
| +
|
| + // If we didn't finish looking through the prefix, we can't strip it.
|
| + if (prefix_index < prefix_to_match.size()) {
|
| + return value;
|
| + }
|
| +
|
| + // Step over any underscores after the prefix
|
| + while (value_index < value.size() && value[value_index] == '_') {
|
| + value_index++;
|
| + }
|
| +
|
| + // If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip.
|
| + if (value_index == value.size()) {
|
| + return value;
|
| + }
|
| +
|
| + return value.substr(value_index);
|
| +}
|
| +
|
| +// Format the enum value name in a pleasant way for C#:
|
| +// - Strip the enum name as a prefix if possible
|
| +// - Convert to PascalCase.
|
| +// For example, an enum called Color with a value of COLOR_BLUE should
|
| +// result in an enum value in C# called just Blue
|
| +std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) {
|
| + std::string stripped = TryRemovePrefix(enum_name, enum_value_name);
|
| + std::string result = ShoutyToPascalCase(stripped);
|
| + // Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned
|
| + // string is a valid identifier.
|
| + if (ascii_isdigit(result[0])) {
|
| + result = "_" + result;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
|
| std::string result = GetFileNamespace(file);
|
| if (result != "") {
|
| @@ -351,49 +451,50 @@ std::string FileDescriptorToBase64(const FileDescriptor* descriptor) {
|
| }
|
|
|
| FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
|
| - int fieldOrdinal) {
|
| + int fieldOrdinal,
|
| + const Options* options) {
|
| switch (descriptor->type()) {
|
| case FieldDescriptor::TYPE_GROUP:
|
| case FieldDescriptor::TYPE_MESSAGE:
|
| if (descriptor->is_repeated()) {
|
| if (descriptor->is_map()) {
|
| - return new MapFieldGenerator(descriptor, fieldOrdinal);
|
| + return new MapFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| - return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal);
|
| + return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal, options);
|
| }
|
| } else {
|
| if (IsWrapperType(descriptor)) {
|
| if (descriptor->containing_oneof()) {
|
| - return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal);
|
| + return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| - return new WrapperFieldGenerator(descriptor, fieldOrdinal);
|
| + return new WrapperFieldGenerator(descriptor, fieldOrdinal, options);
|
| }
|
| } else {
|
| if (descriptor->containing_oneof()) {
|
| - return new MessageOneofFieldGenerator(descriptor, fieldOrdinal);
|
| + return new MessageOneofFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| - return new MessageFieldGenerator(descriptor, fieldOrdinal);
|
| + return new MessageFieldGenerator(descriptor, fieldOrdinal, options);
|
| }
|
| }
|
| }
|
| case FieldDescriptor::TYPE_ENUM:
|
| if (descriptor->is_repeated()) {
|
| - return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal);
|
| + return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| if (descriptor->containing_oneof()) {
|
| - return new EnumOneofFieldGenerator(descriptor, fieldOrdinal);
|
| + return new EnumOneofFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| - return new EnumFieldGenerator(descriptor, fieldOrdinal);
|
| + return new EnumFieldGenerator(descriptor, fieldOrdinal, options);
|
| }
|
| }
|
| default:
|
| if (descriptor->is_repeated()) {
|
| - return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal);
|
| + return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| if (descriptor->containing_oneof()) {
|
| - return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal);
|
| + return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options);
|
| } else {
|
| - return new PrimitiveFieldGenerator(descriptor, fieldOrdinal);
|
| + return new PrimitiveFieldGenerator(descriptor, fieldOrdinal, options);
|
| }
|
| }
|
| }
|
|
|