[Upb C++] Generate class scoped declarations for enumerations.

PiperOrigin-RevId: 512191989
diff --git a/protos_generator/gen_enums.cc b/protos_generator/gen_enums.cc
index e6f866a..e1ad32b 100644
--- a/protos_generator/gen_enums.cc
+++ b/protos_generator/gen_enums.cc
@@ -25,6 +25,11 @@
 
 #include "protos_generator/gen_enums.h"
 
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <vector>
+
 #include "google/protobuf/descriptor.pb.h"
 #include "google/protobuf/descriptor.h"
 #include "protos_generator/gen_utils.h"
@@ -106,10 +111,6 @@
   for (size_t i = 0; i < values.size(); i++) {
     auto value = values[i];
     output("  $0", EnumValueSymbolInNameSpace(desc, value));
-    if (value->options().deprecated()) {
-      output(" ABSL_DEPRECATED(\"Proto enum $0\")",
-             EnumValueSymbolInNameSpace(desc, value));
-    }
     output(" = $0", EnumInt32ToString(value->number()));
     if (i != values.size() - 1) {
       output(",");
diff --git a/protos_generator/gen_enums.h b/protos_generator/gen_enums.h
index 8e7d6ea..00c7ca4 100644
--- a/protos_generator/gen_enums.h
+++ b/protos_generator/gen_enums.h
@@ -34,6 +34,9 @@
 namespace protobuf = ::google::protobuf;
 
 std::string EnumTypeName(const protobuf::EnumDescriptor* enum_descriptor);
+std::string EnumValueSymbolInNameSpace(
+    const protobuf::EnumDescriptor* desc,
+    const protobuf::EnumValueDescriptor* value);
 void WriteHeaderEnumForwardDecls(
     std::vector<const protobuf::EnumDescriptor*>& enums, Output& output);
 void WriteEnumDeclarations(
diff --git a/protos_generator/gen_messages.cc b/protos_generator/gen_messages.cc
index 194fab0..acdbad0 100644
--- a/protos_generator/gen_messages.cc
+++ b/protos_generator/gen_messages.cc
@@ -27,9 +27,13 @@
 
 #include "protos_generator/gen_messages.h"
 
+#include <string>
+#include <vector>
+
 #include "google/protobuf/descriptor.pb.h"
 #include "google/protobuf/descriptor.h"
 #include "protos_generator/gen_accessors.h"
+#include "protos_generator/gen_enums.h"
 #include "protos_generator/gen_extensions.h"
 #include "protos_generator/gen_utils.h"
 #include "protos_generator/output.h"
@@ -45,6 +49,7 @@
 void WriteModelPublicDeclaration(
     const protobuf::Descriptor* descriptor,
     const std::vector<const protobuf::FieldDescriptor*>& file_exts,
+    const std::vector<const protobuf::EnumDescriptor*>& file_enums,
     Output& output);
 void WriteExtensionIdentifiersInClassHeader(
     const protobuf::Descriptor* message,
@@ -62,6 +67,10 @@
     const protobuf::Descriptor* message,
     const std::vector<const protobuf::FieldDescriptor*>& file_exts,
     Output& output);
+void WriteUsingEnumsInHeader(
+    const protobuf::Descriptor* message,
+    const std::vector<const protobuf::EnumDescriptor*>& file_enums,
+    Output& output);
 
 // Writes message class declarations into .upb.proto.h.
 //
@@ -70,6 +79,7 @@
 void WriteMessageClassDeclarations(
     const protobuf::Descriptor* descriptor,
     const std::vector<const protobuf::FieldDescriptor*>& file_exts,
+    const std::vector<const protobuf::EnumDescriptor*>& file_enums,
     Output& output) {
   if (IsMapEntryMessage(descriptor)) {
     // Skip map entry generation. Low level accessors for maps are
@@ -85,7 +95,7 @@
   WriteInternalForwardDeclarationsInHeader(descriptor, output);
   output("\n");
   output("}  // namespace internal\n");
-  WriteModelPublicDeclaration(descriptor, file_exts, output);
+  WriteModelPublicDeclaration(descriptor, file_exts, file_enums, output);
   output("namespace internal {\n");
   WriteModelProxyDeclaration(descriptor, output);
   WriteModelCProxyDeclaration(descriptor, output);
@@ -131,6 +141,7 @@
 void WriteModelPublicDeclaration(
     const protobuf::Descriptor* descriptor,
     const std::vector<const protobuf::FieldDescriptor*>& file_exts,
+    const std::vector<const protobuf::EnumDescriptor*>& file_enums,
     Output& output) {
   output(
       R"cc(
@@ -157,6 +168,7 @@
       ClassName(descriptor));
 
   WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessage, output);
+  WriteUsingEnumsInHeader(descriptor, file_enums, output);
   WriteDefaultInstanceHeader(descriptor, output);
   WriteExtensionIdentifiersInClassHeader(descriptor, file_exts, output);
   output.Indent();
@@ -376,4 +388,42 @@
   }
 }
 
+void WriteUsingEnumsInHeader(
+    const protobuf::Descriptor* message,
+    const std::vector<const protobuf::EnumDescriptor*>& file_enums,
+    Output& output) {
+  for (auto* enum_descriptor : file_enums) {
+    std::string enum_type_name = EnumTypeName(enum_descriptor);
+    std::string enum_resolved_type_name =
+        enum_descriptor->file()->package().empty() &&
+                enum_descriptor->containing_type() == nullptr
+            ? absl::StrCat(kNoPackageNamePrefix,
+                           ToCIdent(enum_descriptor->name()))
+            : enum_type_name;
+    if (enum_descriptor->containing_type() == nullptr ||
+        enum_descriptor->containing_type()->full_name() !=
+            message->full_name()) {
+      continue;
+    }
+    output("using $0", enum_descriptor->name());
+    if (enum_descriptor->options().deprecated()) {
+      output(" ABSL_DEPRECATED(\"Proto enum $0\")", enum_descriptor->name());
+    }
+    output(" = $0;", enum_resolved_type_name);
+    output("\n");
+    int value_count = enum_descriptor->value_count();
+    for (int i = 0; i < value_count; i++) {
+      output("static constexpr $0 $1", enum_descriptor->name(),
+             enum_descriptor->value(i)->name());
+      if (enum_descriptor->options().deprecated() ||
+          enum_descriptor->value(i)->options().deprecated()) {
+        output(" ABSL_DEPRECATED(\"Proto enum value $0\") ",
+               enum_descriptor->value(i)->name());
+      }
+      output(" = $0;\n", EnumValueSymbolInNameSpace(enum_descriptor,
+                                                    enum_descriptor->value(i)));
+    }
+  }
+}
+
 }  // namespace protos_generator
diff --git a/protos_generator/gen_messages.h b/protos_generator/gen_messages.h
index 0b8aa95..bf0ab7c 100644
--- a/protos_generator/gen_messages.h
+++ b/protos_generator/gen_messages.h
@@ -37,6 +37,7 @@
 void WriteMessageClassDeclarations(
     const protobuf::Descriptor* descriptor,
     const std::vector<const protobuf::FieldDescriptor*>& file_exts,
+    const std::vector<const protobuf::EnumDescriptor*>& file_enums,
     Output& output);
 void WriteMessageImplementation(
     const protobuf::Descriptor* descriptor,
diff --git a/protos_generator/protoc-gen-upb-protos.cc b/protos_generator/protoc-gen-upb-protos.cc
index 2e5fbd4..255f65a 100644
--- a/protos_generator/protoc-gen-upb-protos.cc
+++ b/protos_generator/protoc-gen-upb-protos.cc
@@ -171,7 +171,8 @@
   output("\n");
 
   for (auto message : this_file_messages) {
-    WriteMessageClassDeclarations(message, this_file_exts, output);
+    WriteMessageClassDeclarations(message, this_file_exts, this_file_enums,
+                                  output);
   }
   output("\n");
 
diff --git a/protos_generator/tests/test_generated.cc b/protos_generator/tests/test_generated.cc
index d6ca24a..a085de0 100644
--- a/protos_generator/tests/test_generated.cc
+++ b/protos_generator/tests/test_generated.cc
@@ -36,6 +36,7 @@
 using ::protos_generator::test::protos::RED;
 using ::protos_generator::test::protos::TestEnum;
 using ::protos_generator::test::protos::TestModel;
+using ::protos_generator::test::protos::TestModel_Category;
 using ::protos_generator::test::protos::TestModel_Category_IMAGES;
 using ::protos_generator::test::protos::TestModel_Category_NEWS;
 using ::protos_generator::test::protos::TestModel_Category_VIDEO;
@@ -52,6 +53,16 @@
 
 TEST(CppGeneratedCode, EnumNoPackage) { EXPECT_EQ(1, ::protos_CELSIUS); }
 
+TEST(CppGeneratedCode, MessageEnumType) {
+  TestModel_Category category1 = TestModel_Category_IMAGES;
+  TestModel::Category category2 = TestModel::IMAGES;
+  EXPECT_EQ(category1, category2);
+}
+
+TEST(CppGeneratedCode, MessageEnumValue) {
+  EXPECT_EQ(TestModel_Category_IMAGES, TestModel::IMAGES);
+}
+
 TEST(CppGeneratedCode, ArenaConstructor) {
   ::protos::Arena arena;
   auto testModel = ::protos::CreateMessage<TestModel>(arena);