Migrate std::operator+ to Abseil helpers in C# compiler directory.

This also opportunistically migrates many C-style and STL strings to string_view in touched code.

PiperOrigin-RevId: 502773031
pull/11563/head
Mike Kruskal 2 years ago committed by Copybara-Service
parent 85b785c32b
commit 5184022a17
  1. 5
      src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
  2. 2
      src/google/protobuf/compiler/csharp/csharp_enum.cc
  3. 48
      src/google/protobuf/compiler/csharp/csharp_field_base.cc
  4. 4
      src/google/protobuf/compiler/csharp/csharp_generator.cc
  5. 35
      src/google/protobuf/compiler/csharp/csharp_helpers.cc
  6. 11
      src/google/protobuf/compiler/csharp/csharp_helpers.h
  7. 10
      src/google/protobuf/compiler/csharp/csharp_message.cc
  8. 4
      src/google/protobuf/compiler/csharp/csharp_message_field.cc
  9. 11
      src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
  10. 4
      src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
  11. 84
      src/google/protobuf/compiler/csharp/names.cc
  12. 18
      src/google/protobuf/compiler/csharp/names.h

@ -84,7 +84,8 @@ class MockGeneratorContext : public GeneratorContext {
std::string actual_contents;
GOOGLE_ABSL_CHECK_OK(File::GetContentsAsText(
TestSourceDir() + "/" + physical_filename, &actual_contents, true))
absl::StrCat(TestSourceDir(), "/", physical_filename), &actual_contents,
true))
<< "Unable to get " << physical_filename;
EXPECT_TRUE(actual_contents == expected_contents)
<< physical_filename << " needs to be regenerated. Please run "
@ -130,7 +131,7 @@ TEST(CsharpBootstrapTest, GeneratedCsharpDescriptorMatches) {
// only distribution).
std::string descriptor_file_name =
"../csharp/src/Google.Protobuf/Reflection/Descriptor.cs";
if (!File::Exists(TestSourceDir() + "/" + descriptor_file_name)) {
if (!File::Exists(absl::StrCat(TestSourceDir(), "/", descriptor_file_name))) {
return;
}

@ -82,7 +82,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
GOOGLE_ABSL_LOG(WARNING) << "Duplicate enum value " << name << " (originally "
<< original_name << ") in " << descriptor_->name()
<< "; adding underscore to distinguish";
name += "_";
absl::StrAppend(&name, "_");
}
int number = descriptor_->value(i)->number();
if (!used_number.insert(number).second) {

@ -68,7 +68,7 @@ void FieldGeneratorBase::SetCommonFieldVariables(
io::CodedOutputStream::WriteTagToArray(tag, tag_array);
std::string tag_bytes = absl::StrCat(tag_array[0]);
for (int i = 1; i < part_tag_size; i++) {
tag_bytes += ", " + absl::StrCat(tag_array[i]);
absl::StrAppend(&tag_bytes, ", ", tag_array[i]);
}
(*variables)["tag"] = absl::StrCat(tag);
@ -82,7 +82,7 @@ void FieldGeneratorBase::SetCommonFieldVariables(
io::CodedOutputStream::WriteTagToArray(tag, tag_array);
tag_bytes = absl::StrCat(tag_array[0]);
for (int i = 1; i < part_tag_size; i++) {
tag_bytes += ", " + absl::StrCat(tag_array[i]);
absl::StrAppend(&tag_bytes, ", ", tag_array[i]);
}
variables_["end_tag"] = absl::StrCat(tag);
@ -142,11 +142,11 @@ void FieldGeneratorBase::SetCommonOneofFieldVariables(
absl::flat_hash_map<absl::string_view, std::string>* variables) {
(*variables)["oneof_name"] = oneof_name();
if (SupportsPresenceApi(descriptor_)) {
(*variables)["has_property_check"] = "Has" + property_name();
(*variables)["has_property_check"] = absl::StrCat("Has", property_name());
} else {
(*variables)["has_property_check"] =
oneof_name() + "Case_ == " + oneof_property_name() +
"OneofCase." + oneof_case_name();
absl::StrCat(oneof_name(), "Case_ == ", oneof_property_name(),
"OneofCase.", oneof_case_name());
}
(*variables)["oneof_case_name"] = oneof_case_name();
(*variables)["oneof_property_name"] = oneof_property_name();
@ -244,7 +244,7 @@ std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
return wrapped_field_type_name;
} else {
return wrapped_field_type_name + "?";
return absl::StrCat(wrapped_field_type_name, "?");
}
}
return GetClassName(descriptor->message_type());
@ -326,7 +326,7 @@ bool FieldGeneratorBase::has_default_value() {
}
}
bool AllPrintableAscii(const std::string& text) {
bool AllPrintableAscii(absl::string_view text) {
for(int i = 0; i < text.size(); i++) {
if (text[i] < 0x20 || text[i] > 0x7e) {
return false;
@ -338,17 +338,19 @@ bool AllPrintableAscii(const std::string& text) {
std::string FieldGeneratorBase::GetStringDefaultValueInternal(const FieldDescriptor* descriptor) {
if (descriptor->default_value_string().empty())
return "\"\"";
else
return "global::System.Text.Encoding.UTF8.GetString(global::System."
"Convert.FromBase64String(\"" +
StringToBase64(descriptor->default_value_string()) + "\"), 0, " + absl::StrCat(descriptor->default_value_string().length()) + ")";
return absl::StrCat(
"global::System.Text.Encoding.UTF8.GetString(global::System."
"Convert.FromBase64String(\"",
StringToBase64(descriptor->default_value_string()), "\"), 0, ",
descriptor->default_value_string().length(), ")");
}
std::string FieldGeneratorBase::GetBytesDefaultValueInternal(const FieldDescriptor* descriptor) {
if (descriptor->default_value_string().empty())
return "pb::ByteString.Empty";
else
return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor->default_value_string()) + "\")";
return absl::StrCat("pb::ByteString.FromBase64(\"",
StringToBase64(descriptor->default_value_string()),
"\")");
}
std::string FieldGeneratorBase::default_value() {
@ -358,8 +360,10 @@ std::string FieldGeneratorBase::default_value() {
std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM:
return GetClassName(descriptor->default_value_enum()->type()) + "." +
GetEnumValueName(descriptor->default_value_enum()->type()->name(), descriptor->default_value_enum()->name());
return absl::StrCat(
GetClassName(descriptor->default_value_enum()->type()), ".",
GetEnumValueName(descriptor->default_value_enum()->type()->name(),
descriptor->default_value_enum()->name()));
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
if (IsWrapperType(descriptor)) {
@ -377,7 +381,7 @@ std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor)
} else if (std::isnan(value)) {
return "double.NaN";
}
return absl::StrCat(value) + "D";
return absl::StrCat(value, "D");
}
case FieldDescriptor::TYPE_FLOAT: {
float value = descriptor->default_value_float();
@ -388,16 +392,16 @@ std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor)
} else if (std::isnan(value)) {
return "float.NaN";
}
return absl::StrCat(value) + "F";
return absl::StrCat(value, "F");
}
case FieldDescriptor::TYPE_INT64:
return absl::StrCat(descriptor->default_value_int64()) + "L";
return absl::StrCat(descriptor->default_value_int64(), "L");
case FieldDescriptor::TYPE_UINT64:
return absl::StrCat(descriptor->default_value_uint64()) + "UL";
return absl::StrCat(descriptor->default_value_uint64(), "UL");
case FieldDescriptor::TYPE_INT32:
return absl::StrCat(descriptor->default_value_int32());
case FieldDescriptor::TYPE_FIXED64:
return absl::StrCat(descriptor->default_value_uint64()) + "UL";
return absl::StrCat(descriptor->default_value_uint64(), "UL");
case FieldDescriptor::TYPE_FIXED32:
return absl::StrCat(descriptor->default_value_uint32());
case FieldDescriptor::TYPE_BOOL:
@ -415,11 +419,11 @@ std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor)
case FieldDescriptor::TYPE_SFIXED32:
return absl::StrCat(descriptor->default_value_int32());
case FieldDescriptor::TYPE_SFIXED64:
return absl::StrCat(descriptor->default_value_int64()) + "L";
return absl::StrCat(descriptor->default_value_int64(), "L");
case FieldDescriptor::TYPE_SINT32:
return absl::StrCat(descriptor->default_value_int32());
case FieldDescriptor::TYPE_SINT64:
return absl::StrCat(descriptor->default_value_int64()) + "L";
return absl::StrCat(descriptor->default_value_int64(), "L");
default:
GOOGLE_ABSL_LOG(FATAL) << "Unknown field type.";
return "";

@ -69,7 +69,7 @@ bool Generator::Generate(const FileDescriptor* file,
struct Options cli_options;
for (int i = 0; i < options.size(); i++) {
for (size_t i = 0; i < options.size(); i++) {
if (options[i].first == "file_extension") {
cli_options.file_extension = options[i].second;
} else if (options[i].first == "base_namespace") {
@ -80,7 +80,7 @@ bool Generator::Generate(const FileDescriptor* file,
} else if (options[i].first == "serializable") {
cli_options.serializable = true;
} else {
*error = "Unknown generator option: " + options[i].first;
*error = absl::StrCat("Unknown generator option: ", options[i].first);
return false;
}
}

@ -37,6 +37,7 @@
#include <algorithm>
#include <limits>
#include <sstream>
#include <string>
#include <vector>
#include "absl/container/flat_hash_set.h"
@ -121,7 +122,7 @@ CSharpType GetCSharpType(FieldDescriptor::Type type) {
// Numeric Alphanumeric Upper
// Lower letter Alphanumeric Same as current
// Upper letter Alphanumeric Lower
std::string ShoutyToPascalCase(const std::string& input) {
std::string ShoutyToPascalCase(absl::string_view input) {
std::string result;
// Simple way of implementing "always start with upper"
char previous = '_';
@ -151,7 +152,7 @@ std::string ShoutyToPascalCase(const std::string& input) {
// (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) {
std::string TryRemovePrefix(absl::string_view prefix, absl::string_view 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++) {
@ -171,13 +172,13 @@ std::string TryRemovePrefix(const std::string& prefix, const std::string& value)
}
if (absl::ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) {
// Failed to match the prefix - bail out early.
return value;
return std::string(value);
}
}
// If we didn't finish looking through the prefix, we can't strip it.
if (prefix_index < prefix_to_match.size()) {
return value;
return std::string(value);
}
// Step over any underscores after the prefix
@ -187,10 +188,10 @@ std::string TryRemovePrefix(const std::string& prefix, const std::string& value)
// 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 std::string(value);
}
return value.substr(value_index);
return std::string(value.substr(value_index));
}
// Format the enum value name in a pleasant way for C#:
@ -198,13 +199,14 @@ std::string TryRemovePrefix(const std::string& prefix, const std::string& value)
// - 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 GetEnumValueName(absl::string_view enum_name,
absl::string_view 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 (absl::ascii_isdigit(result[0])) {
result = "_" + result;
return absl::StrCat("_", result);
}
return result;
}
@ -249,11 +251,12 @@ uint GetGroupEndTag(const Descriptor* descriptor) {
std::string GetFullExtensionName(const FieldDescriptor* descriptor) {
if (descriptor->extension_scope()) {
return GetClassName(descriptor->extension_scope()) + ".Extensions." + GetPropertyName(descriptor);
}
else {
return GetExtensionClassUnqualifiedName(descriptor->file()) + "." + GetPropertyName(descriptor);
return absl::StrCat(GetClassName(descriptor->extension_scope()),
".Extensions.", GetPropertyName(descriptor));
}
return absl::StrCat(GetExtensionClassUnqualifiedName(descriptor->file()), ".",
GetPropertyName(descriptor));
}
// Groups are hacky: The name of the field is just the lower-cased name
@ -268,7 +271,7 @@ std::string GetFieldName(const FieldDescriptor* descriptor) {
}
std::string GetFieldConstantName(const FieldDescriptor* field) {
return GetPropertyName(field) + "FieldNumber";
return absl::StrCat(GetPropertyName(field), "FieldNumber");
}
std::string GetPropertyName(const FieldDescriptor* descriptor) {
@ -296,7 +299,7 @@ std::string GetPropertyName(const FieldDescriptor* descriptor) {
// warnings, but not errors; changing the name now could be a breaking change.
if (property_name == descriptor->containing_type()->name()
|| reserved_member_names.find(property_name) != reserved_member_names.end()) {
property_name += "_";
absl::StrAppend(&property_name, "_");
}
return property_name;
}
@ -344,10 +347,10 @@ int GetFixedSize(FieldDescriptor::Type type) {
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string StringToBase64(const std::string& input) {
std::string StringToBase64(absl::string_view input) {
std::string result;
size_t remaining = input.size();
const unsigned char *src = (const unsigned char*) input.c_str();
const unsigned char* src = (const unsigned char*)input.data();
while (remaining > 2) {
result += base64_chars[src[0] >> 2];
result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];

@ -38,13 +38,14 @@
#include <string>
#include "google/protobuf/compiler/code_generator.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/port.h"
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/port.h"
#include "google/protobuf/port_def.inc"
#include "google/protobuf/stubs/common.h"
namespace google {
namespace protobuf {
@ -85,11 +86,11 @@ int GetFixedSize(FieldDescriptor::Type type);
// Note that we wouldn't normally want to export this (we're not expecting
// it to be used outside libprotoc itself) but this exposes it for testing.
std::string PROTOC_EXPORT GetEnumValueName(const std::string& enum_name,
const std::string& enum_value_name);
std::string PROTOC_EXPORT GetEnumValueName(absl::string_view enum_name,
absl::string_view enum_value_name);
// TODO(jtattermusch): perhaps we could move this to strutil
std::string StringToBase64(const std::string& input);
std::string StringToBase64(absl::string_view input);
std::string FileDescriptorToBase64(const FileDescriptor* descriptor);

@ -175,11 +175,13 @@ void MessageGenerator::Generate(io::Printer* printer) {
// Access the message descriptor via the relevant file descriptor or containing message descriptor.
if (!descriptor_->containing_type()) {
vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file())
+ ".Descriptor.MessageTypes[" + absl::StrCat(descriptor_->index()) + "]";
vars["descriptor_accessor"] =
absl::StrCat(GetReflectionClassName(descriptor_->file()),
".Descriptor.MessageTypes[", descriptor_->index(), "]");
} else {
vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
+ ".Descriptor.NestedTypes[" + absl::StrCat(descriptor_->index()) + "]";
vars["descriptor_accessor"] =
absl::StrCat(GetClassName(descriptor_->containing_type()),
".Descriptor.NestedTypes[", descriptor_->index(), "]");
}
WriteGeneratedCodeAttributes(printer);

@ -50,8 +50,8 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options *options)
: FieldGeneratorBase(descriptor, presenceIndex, options) {
if (!SupportsPresenceApi(descriptor_)) {
variables_["has_property_check"] = name() + "_ != null";
variables_["has_not_property_check"] = name() + "_ == null";
variables_["has_property_check"] = absl::StrCat(name(), "_ != null");
variables_["has_not_property_check"] = absl::StrCat(name(), "_ == null");
}
}

@ -31,6 +31,7 @@
#include "google/protobuf/compiler/csharp/csharp_primitive_field.h"
#include <sstream>
#include <string>
#include "google/protobuf/compiler/code_generator.h"
#include "absl/strings/str_cat.h"
@ -53,8 +54,11 @@ PrimitiveFieldGenerator::PrimitiveFieldGenerator(
is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING
&& descriptor->type() != FieldDescriptor::TYPE_BYTES;
if (!is_value_type && !SupportsPresenceApi(descriptor_)) {
variables_["has_property_check"] = variables_["property_name"] + ".Length != 0";
variables_["other_has_property_check"] = "other." + variables_["property_name"] + ".Length != 0";
std::string property_name = variables_["property_name"];
variables_["has_property_check"] =
absl::StrCat(property_name, ".Length != 0");
variables_["other_has_property_check"] =
absl::StrCat("other.", property_name, ".Length != 0");
}
}
@ -80,8 +84,9 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
"private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n");
std::string property_name = variables_["property_name"];
variables_["default_value_access"] =
variables_["property_name"] + "DefaultValue";
absl::StrCat(property_name, "DefaultValue");
} else {
variables_["default_value_access"] = variables_["default_value"];
}

@ -49,8 +49,8 @@ namespace csharp {
WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
int presenceIndex, const Options *options)
: FieldGeneratorBase(descriptor, presenceIndex, options) {
variables_["has_property_check"] = name() + "_ != null";
variables_["has_not_property_check"] = name() + "_ == null";
variables_["has_property_check"] = absl::StrCat(name(), "_ != null");
variables_["has_not_property_check"] = absl::StrCat(name(), "_ == null");
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
wrapped_field->type() != FieldDescriptor::TYPE_BYTES;

@ -36,7 +36,10 @@
#include <string>
#include "absl/strings/match.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.pb.h"
@ -50,7 +53,7 @@ namespace csharp {
namespace {
std::string StripDotProto(const std::string& proto_file) {
absl::string_view StripDotProto(absl::string_view proto_file) {
int lastindex = proto_file.find_last_of('.');
return proto_file.substr(0, lastindex);
}
@ -64,21 +67,21 @@ std::string GetFileNameBase(const FileDescriptor* descriptor) {
return UnderscoresToPascalCase(StripDotProto(base));
}
std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
std::string result = GetFileNamespace(file);
if (!result.empty()) {
result += '.';
}
std::string classname;
if (file->package().empty()) {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.substr(file->package().size() + 1);
}
result += absl::StrReplaceAll(classname, {{".", ".Types."}});
return "global::" + result;
std::string ToCSharpName(absl::string_view name, const FileDescriptor* file) {
std::string result = GetFileNamespace(file);
if (!result.empty()) {
result += '.';
}
absl::string_view classname;
if (file->package().empty()) {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.substr(file->package().size() + 1);
}
return absl::StrCat("global::", result,
absl::StrReplaceAll(classname, {{".", ".Types."}}));
}
} // namespace
@ -101,7 +104,7 @@ std::string GetClassName(const EnumDescriptor* descriptor) {
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Reflection";
return absl::StrCat(GetFileNameBase(descriptor), "Reflection");
}
std::string GetReflectionClassName(const FileDescriptor* descriptor) {
@ -109,59 +112,54 @@ std::string GetReflectionClassName(const FileDescriptor* descriptor) {
if (!result.empty()) {
result += '.';
}
result += GetReflectionClassUnqualifiedName(descriptor);
return "global::" + result;
return absl::StrCat("global::", result,
GetReflectionClassUnqualifiedName(descriptor));
}
std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Extensions";
return absl::StrCat(GetFileNameBase(descriptor), "Extensions");
}
std::string GetOutputFile(const FileDescriptor* descriptor,
const std::string file_extension,
const bool generate_directories,
const std::string base_namespace,
absl::string_view file_extension,
bool generate_directories,
absl::string_view base_namespace,
std::string* error) {
std::string relative_filename = GetFileNameBase(descriptor) + file_extension;
std::string relative_filename =
absl::StrCat(GetFileNameBase(descriptor), file_extension);
if (!generate_directories) {
return relative_filename;
}
std::string ns = GetFileNamespace(descriptor);
std::string namespace_suffix = ns;
absl::string_view namespace_suffix = ns;
if (!base_namespace.empty()) {
// Check that the base_namespace is either equal to or a leading part of
// the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
// be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
// to both.
std::string extended_ns = ns + ".";
if (extended_ns.find(base_namespace + ".") != 0) {
*error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
return ""; // This will be ignored, because we've set an error.
}
namespace_suffix = ns.substr(base_namespace.length());
if (namespace_suffix.find('.') == 0) {
namespace_suffix = namespace_suffix.substr(1);
if (!absl::ConsumePrefix(&namespace_suffix, base_namespace) ||
(!namespace_suffix.empty() &&
!absl::ConsumePrefix(&namespace_suffix, "."))) {
*error = absl::StrCat("Namespace ", ns,
" is not a prefix namespace of base namespace ",
base_namespace);
return ""; // This will be ignored, because we've set an error.
}
}
std::string namespace_dir =
absl::StrReplaceAll(namespace_suffix, {{".", "/"}});
if (!namespace_dir.empty()) {
namespace_dir += "/";
}
return namespace_dir + relative_filename;
return absl::StrCat(absl::StrReplaceAll(namespace_suffix, {{".", "/"}}),
namespace_suffix.empty() ? "" : "/", relative_filename);
}
std::string UnderscoresToPascalCase(const std::string& input) {
std::string UnderscoresToPascalCase(absl::string_view input) {
return UnderscoresToCamelCase(input, true);
}
// TODO(jtattermusch): can we reuse a utility function?
std::string UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period) {
std::string UnderscoresToCamelCase(absl::string_view input,
bool cap_next_letter, bool preserve_period) {
std::string result;
// Note: I distrust ctype.h due to locales.

@ -40,6 +40,7 @@
#include <string>
#include "absl/strings/string_view.h"
#include "google/protobuf/port_def.inc"
namespace google {
@ -118,20 +119,21 @@ GetReflectionClassName(const FileDescriptor* descriptor);
// of failure, this function will return empty string and error parameter
// will contain the error message.
std::string PROTOC_EXPORT GetOutputFile(const FileDescriptor* descriptor,
const std::string file_extension,
const bool generate_directories,
const std::string base_namespace,
absl::string_view file_extension,
bool generate_directories,
absl::string_view base_namespace,
std::string* error);
std::string UnderscoresToPascalCase(const std::string& input);
std::string UnderscoresToPascalCase(absl::string_view input);
// Note that we wouldn't normally want to export this (we're not expecting
// it to be used outside libprotoc itself) but this exposes it for testing.
std::string PROTOC_EXPORT UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period);
std::string PROTOC_EXPORT UnderscoresToCamelCase(absl::string_view input,
bool cap_next_letter,
bool preserve_period);
inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
inline std::string UnderscoresToCamelCase(absl::string_view input,
bool cap_next_letter) {
return UnderscoresToCamelCase(input, cap_next_letter, false);
}

Loading…
Cancel
Save