[Upb C++] Update generator to create oneof_case() accessor and OneOfCase enumerations.

PiperOrigin-RevId: 512197371
pull/13171/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent a35491fa55
commit 1b6beaa53d
  1. 44
      protos_generator/gen_accessors.cc
  2. 2
      protos_generator/gen_accessors.h
  3. 1
      protos_generator/gen_messages.cc
  4. 26
      protos_generator/gen_utils.cc
  5. 4
      protos_generator/gen_utils.h
  6. 7
      protos_generator/tests/test_generated.cc

@ -672,9 +672,53 @@ void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc,
}
}
}
for (int i = 0; i < desc->real_oneof_decl_count(); ++i) {
const protobuf::OneofDescriptor* oneof = desc->oneof_decl(i);
output("using $0Access::$1_case;\n", class_name, oneof->name());
output("using $0Access::$1Case;\n", class_name,
ToCamelCase(oneof->name(), /*lower_first=*/false));
for (int j = 0; j < oneof->field_count(); ++j) {
const protobuf::FieldDescriptor* field = oneof->field(j);
output("using $0Access::k$1;\n", class_name,
ToCamelCase(field->name(), /*lower_first=*/false),
field->number());
}
output("using $0Access::$1_NOT_SET;\n", class_name,
absl::AsciiStrToUpper(oneof->name()));
}
output("using $0Access::msg;\n", class_name);
}
void WriteOneofAccessorsInHeader(const protobuf::Descriptor* desc,
Output& output) {
// Generate const methods.
OutputIndenter i(output);
std::string class_name = ClassName(desc);
auto field_names = CreateFieldNameMap(desc);
for (int i = 0; i < desc->real_oneof_decl_count(); ++i) {
const protobuf::OneofDescriptor* oneof = desc->oneof_decl(i);
output("enum $0Case {\n",
ToCamelCase(oneof->name(), /*lower_first=*/false));
for (int j = 0; j < oneof->field_count(); ++j) {
const protobuf::FieldDescriptor* field = oneof->field(j);
output(" k$0 = $1,\n", ToCamelCase(field->name(), /*lower_first=*/false),
field->number());
}
output(" $0_NOT_SET = 0,\n", absl::AsciiStrToUpper(oneof->name()));
output("};\n\n");
output("$0Case $1_case() const {\n",
ToCamelCase(oneof->name(), /*lower_first=*/false), oneof->name());
for (int j = 0; j < oneof->field_count(); ++j) {
const protobuf::FieldDescriptor* field = oneof->field(j);
std::string resolved_field_name = ResolveFieldName(field, field_names);
output(" if (has_$0()) { return k$1; }\n", resolved_field_name,
ToCamelCase(field->name(), /*lower_first=*/false));
}
output(" return $0_NOT_SET;\n", absl::AsciiStrToUpper(oneof->name()));
output("}\n;");
}
}
std::string ResolveFieldName(const protobuf::FieldDescriptor* field,
const NameToFieldDescriptorMap& field_names) {
// C++ implementation specific reserved names.

@ -39,6 +39,8 @@ void WriteFieldAccessorsInHeader(const protobuf::Descriptor* desc,
void WriteAccessorsInSource(const protobuf::Descriptor* desc, Output& output);
void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc,
MessageClassType handle_type, Output& output);
void WriteOneofAccessorsInHeader(const protobuf::Descriptor* desc,
Output& output);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_ACCESSORS_H_

@ -117,6 +117,7 @@ void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor,
)cc",
ClassName(descriptor), MessageName(descriptor));
WriteFieldAccessorsInHeader(descriptor, output);
WriteOneofAccessorsInHeader(descriptor, output);
output.Indent();
output(
R"cc(

@ -27,6 +27,7 @@
#include "protos_generator/gen_utils.h"
#include <algorithm>
#include <string>
#include "absl/log/absl_check.h"
@ -264,6 +265,7 @@ std::vector<const protobuf::FieldDescriptor*> SortedExtensions(
std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder(
const protobuf::Descriptor* message) {
std::vector<const protobuf::FieldDescriptor*> fields;
fields.reserve(message->field_count());
for (int i = 0; i < message->field_count(); i++) {
fields.push_back(message->field(i));
}
@ -275,4 +277,28 @@ std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder(
return fields;
}
std::string ToCamelCase(const std::string& input, bool lower_first) {
bool capitalize_next = !lower_first;
std::string result;
result.reserve(input.size());
for (char character : input) {
if (character == '_') {
capitalize_next = true;
} else if (capitalize_next) {
result.push_back(absl::ascii_toupper(character));
capitalize_next = false;
} else {
result.push_back(character);
}
}
// Lower-case the first letter.
if (lower_first && !result.empty()) {
result[0] = absl::ascii_tolower(result[0]);
}
return result;
}
} // namespace protos_generator

@ -28,6 +28,8 @@
#ifndef UPB_PROTOS_GENERATOR_GEN_UTILS_H_
#define UPB_PROTOS_GENERATOR_GEN_UTILS_H_
#include <vector>
#include "google/protobuf/descriptor.pb.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
@ -88,6 +90,8 @@ std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder(
inline constexpr absl::string_view kNoPackageNamePrefix = "protos_";
std::string ToCamelCase(const std::string& input, bool lower_first);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_GEN_UTILS_H_

@ -24,6 +24,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
#include <memory>
#include "gtest/gtest.h"
#include "protos/protos.h"
@ -271,22 +272,26 @@ TEST(CppGeneratedCode, OneOfFields) {
EXPECT_FALSE(test_model.has_oneof_member1());
EXPECT_FALSE(test_model.has_oneof_member2());
EXPECT_EQ(TestModel::CHILD_ONEOF1_NOT_SET, test_model.child_oneof1_case());
test_model.set_oneof_member1("one of string");
EXPECT_TRUE(test_model.has_oneof_member1());
EXPECT_FALSE(test_model.has_oneof_member2());
EXPECT_EQ(test_model.oneof_member1(), "one of string");
EXPECT_EQ(TestModel::kOneofMember1, test_model.child_oneof1_case());
test_model.set_oneof_member2(true);
EXPECT_FALSE(test_model.has_oneof_member1());
EXPECT_TRUE(test_model.has_oneof_member2());
EXPECT_EQ(test_model.oneof_member2(), true);
EXPECT_EQ(TestModel::kOneofMember2, test_model.child_oneof1_case());
test_model.clear_oneof_member2();
EXPECT_FALSE(test_model.has_oneof_member1());
EXPECT_FALSE(test_model.has_oneof_member2());
EXPECT_EQ(test_model.oneof_member1(), "");
EXPECT_EQ(test_model.oneof_member2(), false);
EXPECT_EQ(TestModel::CHILD_ONEOF1_NOT_SET, test_model.child_oneof1_case());
}
TEST(CppGeneratedCode, Messages) {
@ -619,7 +624,7 @@ TEST(CppGeneratedCode, SharedPointer) {
}
TEST(CppGeneratedCode, UniquePointer) {
std::unique_ptr<TestModel> model = std::make_unique<TestModel>();
auto model = std::make_unique<TestModel>();
::upb::Arena arena;
auto bytes = protos::Serialize(model, arena);
EXPECT_TRUE(protos::Parse(model, bytes.value()));

Loading…
Cancel
Save