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

PiperOrigin-RevId: 512197371
diff --git a/protos_generator/gen_accessors.cc b/protos_generator/gen_accessors.cc
index a6cfe53..9f599cc 100644
--- a/protos_generator/gen_accessors.cc
+++ b/protos_generator/gen_accessors.cc
@@ -672,9 +672,53 @@
       }
     }
   }
+  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.
diff --git a/protos_generator/gen_accessors.h b/protos_generator/gen_accessors.h
index 070cb88..64df523 100644
--- a/protos_generator/gen_accessors.h
+++ b/protos_generator/gen_accessors.h
@@ -39,6 +39,8 @@
 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_
diff --git a/protos_generator/gen_messages.cc b/protos_generator/gen_messages.cc
index acdbad0..2af76ff 100644
--- a/protos_generator/gen_messages.cc
+++ b/protos_generator/gen_messages.cc
@@ -117,6 +117,7 @@
       )cc",
       ClassName(descriptor), MessageName(descriptor));
   WriteFieldAccessorsInHeader(descriptor, output);
+  WriteOneofAccessorsInHeader(descriptor, output);
   output.Indent();
   output(
       R"cc(
diff --git a/protos_generator/gen_utils.cc b/protos_generator/gen_utils.cc
index 4ab3572..53630fd 100644
--- a/protos_generator/gen_utils.cc
+++ b/protos_generator/gen_utils.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*> 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 @@
   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
diff --git a/protos_generator/gen_utils.h b/protos_generator/gen_utils.h
index 5563f9f..394c244 100644
--- a/protos_generator/gen_utils.h
+++ b/protos_generator/gen_utils.h
@@ -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 @@
 
 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_
diff --git a/protos_generator/tests/test_generated.cc b/protos_generator/tests/test_generated.cc
index a085de0..c7a4258 100644
--- a/protos_generator/tests/test_generated.cc
+++ b/protos_generator/tests/test_generated.cc
@@ -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 @@
 
   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, 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()));