Enumerators can be deprecated

dumpapi/compile support @deprecated in the comments of enumerators.

Bug: 218401941
Test: aidl_integration_test (golden_output)
Change-Id: Ifa8266429ace130c4ab12cfda11f43273d2d0e90
diff --git a/aidl_dumpapi.cpp b/aidl_dumpapi.cpp
index 30f65dc..1451d41 100644
--- a/aidl_dumpapi.cpp
+++ b/aidl_dumpapi.cpp
@@ -119,6 +119,7 @@
   out << "enum " << t.GetName() << " {\n";
   out.Indent();
   for (const auto& e : t.GetEnumerators()) {
+    DumpComments(*e);
     out << e->GetName() << " = ";
     DumpConstantValue(t.GetBackingType(), *e->GetValue());
     out << ",\n";
diff --git a/aidl_to_cpp_common.cpp b/aidl_to_cpp_common.cpp
index 030b13e..589bb55 100644
--- a/aidl_to_cpp_common.cpp
+++ b/aidl_to_cpp_common.cpp
@@ -219,13 +219,26 @@
   out << " " << enum_decl.GetName() << " : " << backing_type << " {\n";
   out.Indent();
   for (const auto& enumerator : enum_decl.GetEnumerators()) {
-    out << enumerator->GetName() << " = "
-        << enumerator->ValueString(enum_decl.GetBackingType(), decorator) << ",\n";
+    out << enumerator->GetName();
+    GenerateDeprecated(out, *enumerator);
+    out << " = " << enumerator->ValueString(enum_decl.GetBackingType(), decorator) << ",\n";
   }
   out.Dedent();
   out << "};\n";
 }
 
+static bool IsEnumDeprecated(const AidlEnumDeclaration& enum_decl) {
+  if (enum_decl.IsDeprecated()) {
+    return true;
+  }
+  for (const auto& e : enum_decl.GetEnumerators()) {
+    if (e->IsDeprecated()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // enum_values template value is defined in its own namespace (android::internal or ndk::internal),
 // so the enum_decl type should be fully qualified.
 std::string GenerateEnumValues(const AidlEnumDeclaration& enum_decl,
@@ -237,9 +250,11 @@
   std::ostringstream code;
   code << "#pragma clang diagnostic push\n";
   code << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
+  if (IsEnumDeprecated(enum_decl)) {
+    code << "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n";
+  }
   code << "template <>\n";
   code << "constexpr inline std::array<" << fq_name << ", " << size << ">";
-  GenerateDeprecated(code, enum_decl);
   code << " enum_values<" << fq_name << "> = {\n";
   for (const auto& enumerator : enum_decl.GetEnumerators()) {
     code << "  " << fq_name << "::" << enumerator->GetName() << ",\n";
@@ -255,14 +270,12 @@
                                  const std::string& backing_type) {
   const auto q_name = GetQualifiedName(enum_decl);
   std::ostringstream code;
-  const std::string signature =
-      "[[nodiscard]] static inline std::string toString(" + q_name + " val)";
-  if (enum_decl.IsDeprecated()) {
-    code << signature;
-    GenerateDeprecated(code, enum_decl);
-    code << ";\n";
+  bool is_enum_deprecated = IsEnumDeprecated(enum_decl);
+  if (is_enum_deprecated) {
+    code << "#pragma clang diagnostic push\n";
+    code << "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n";
   }
-  code << signature << " {\n";
+  code << "[[nodiscard]] static inline std::string toString(" + q_name + " val) {\n";
   code << "  switch(val) {\n";
   std::set<std::string> unique_cases;
   for (const auto& enumerator : enum_decl.GetEnumerators()) {
@@ -281,6 +294,9 @@
   code << "    return std::to_string(static_cast<" << backing_type << ">(val));\n";
   code << "  }\n";
   code << "}\n";
+  if (is_enum_deprecated) {
+    code << "#pragma clang diagnostic pop\n";
+  }
   return code.str();
 }
 
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 5836b9b..4f94b16 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -1146,6 +1146,19 @@
                       {Options::Language::NDK, {"out/aidl/Foo.h", "__attribute__((deprecated"}},
                       {Options::Language::RUST, {"out/Foo.rs", "#[deprecated"}},
                   });
+
+  CheckDeprecated("Foo.aidl",
+                  "enum Foo {\n"
+                  " /** @deprecated */\n"
+                  " FOO,\n"
+                  " BAR,\n"
+                  "}",
+                  {
+                      {Options::Language::JAVA, {"out/Foo.java", "@Deprecated"}},
+                      {Options::Language::CPP, {"out/Foo.h", "__attribute__((deprecated"}},
+                      {Options::Language::NDK, {"out/aidl/Foo.h", "__attribute__((deprecated"}},
+                      {Options::Language::RUST, {"out/Foo.rs", "#[deprecated"}},
+                  });
 }
 
 TEST_P(AidlTest, RequireOuterClass) {
diff --git a/generate_java.cpp b/generate_java.cpp
index 1d21792..8dc1643 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -942,6 +942,11 @@
   void Visit(const AidlStructuredParcelable& t) override { ForDefinedType(t); }
   void Visit(const AidlUnionDecl& t) override { ForDefinedType(t); }
   void Visit(const AidlEnumDeclaration& t) override { ForDefinedType(t); }
+  void Visit(const AidlEnumerator& e) override {
+    if (e.IsDeprecated()) {
+      result.push_back("@Deprecated");
+    }
+  }
   void Visit(const AidlMethod& m) override { ForMember(m); }
   void Visit(const AidlConstantDeclaration& c) override { ForMember(c); }
   void Visit(const AidlVariableDeclaration& v) override { ForMember(v); }
diff --git a/generate_rust.cpp b/generate_rust.cpp
index 725cf0e..5316c45 100644
--- a/generate_rust.cpp
+++ b/generate_rust.cpp
@@ -1108,6 +1108,7 @@
   code_writer->Indent();
   for (const auto& enumerator : enum_decl->GetEnumerators()) {
     auto value = enumerator->GetValue()->ValueString(aidl_backing_type, ConstantValueDecorator);
+    GenerateDeprecated(*code_writer, *enumerator);
     *code_writer << enumerator->GetName() << " = " << value << ",\n";
   }
   code_writer->Dedent();
diff --git a/tests/android/aidl/tests/IntEnum.aidl b/tests/android/aidl/tests/IntEnum.aidl
index d9ae6b3..b241871 100644
--- a/tests/android/aidl/tests/IntEnum.aidl
+++ b/tests/android/aidl/tests/IntEnum.aidl
@@ -21,4 +21,6 @@
     FOO = 1000,
     BAR = 2000,
     BAZ,
+    /** @deprecated do not use this */
+    QUX,
 }
diff --git a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/DeprecatedEnum.h b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/DeprecatedEnum.h
index c89b38f..593eaea 100644
--- a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/DeprecatedEnum.h
+++ b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/DeprecatedEnum.h
@@ -19,7 +19,8 @@
 namespace android {
 namespace aidl {
 namespace tests {
-[[nodiscard]] static inline std::string toString(DeprecatedEnum val) __attribute__((deprecated("test")));
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 [[nodiscard]] static inline std::string toString(DeprecatedEnum val) {
   switch(val) {
   case DeprecatedEnum::A:
@@ -32,6 +33,7 @@
     return std::to_string(static_cast<int32_t>(val));
   }
 }
+#pragma clang diagnostic pop
 }  // namespace tests
 }  // namespace aidl
 }  // namespace android
@@ -39,8 +41,9 @@
 namespace internal {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc++17-extensions"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 template <>
-constexpr inline std::array<::android::aidl::tests::DeprecatedEnum, 3> __attribute__((deprecated("test"))) enum_values<::android::aidl::tests::DeprecatedEnum> = {
+constexpr inline std::array<::android::aidl::tests::DeprecatedEnum, 3> enum_values<::android::aidl::tests::DeprecatedEnum> = {
   ::android::aidl::tests::DeprecatedEnum::A,
   ::android::aidl::tests::DeprecatedEnum::B,
   ::android::aidl::tests::DeprecatedEnum::C,
diff --git a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/IntEnum.h b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/IntEnum.h
index 00e8738..2e57678 100644
--- a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/IntEnum.h
+++ b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/IntEnum.h
@@ -12,6 +12,7 @@
   FOO = 1000,
   BAR = 2000,
   BAZ = 2001,
+  QUX __attribute__((deprecated("do not use this"))) = 2002,
 };
 }  // namespace tests
 }  // namespace aidl
@@ -19,6 +20,8 @@
 namespace android {
 namespace aidl {
 namespace tests {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 [[nodiscard]] static inline std::string toString(IntEnum val) {
   switch(val) {
   case IntEnum::FOO:
@@ -27,10 +30,13 @@
     return "BAR";
   case IntEnum::BAZ:
     return "BAZ";
+  case IntEnum::QUX:
+    return "QUX";
   default:
     return std::to_string(static_cast<int32_t>(val));
   }
 }
+#pragma clang diagnostic pop
 }  // namespace tests
 }  // namespace aidl
 }  // namespace android
@@ -38,11 +44,13 @@
 namespace internal {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc++17-extensions"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 template <>
-constexpr inline std::array<::android::aidl::tests::IntEnum, 3> enum_values<::android::aidl::tests::IntEnum> = {
+constexpr inline std::array<::android::aidl::tests::IntEnum, 4> enum_values<::android::aidl::tests::IntEnum> = {
   ::android::aidl::tests::IntEnum::FOO,
   ::android::aidl::tests::IntEnum::BAR,
   ::android::aidl::tests::IntEnum::BAZ,
+  ::android::aidl::tests::IntEnum::QUX,
 };
 #pragma clang diagnostic pop
 }  // namespace internal
diff --git a/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/IntEnum.java b/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/IntEnum.java
index 64ae00a..0e2dd06 100644
--- a/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/IntEnum.java
+++ b/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/IntEnum.java
@@ -6,4 +6,7 @@
   public static final int FOO = 1000;
   public static final int BAR = 2000;
   public static final int BAZ = 2001;
+  /** @deprecated do not use this */
+  @Deprecated
+  public static final int QUX = 2002;
 }
diff --git a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/DeprecatedEnum.h b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/DeprecatedEnum.h
index 299874c..fce736b 100644
--- a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/DeprecatedEnum.h
+++ b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/DeprecatedEnum.h
@@ -29,7 +29,8 @@
 namespace android {
 namespace aidl {
 namespace tests {
-[[nodiscard]] static inline std::string toString(DeprecatedEnum val) __attribute__((deprecated("test")));
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 [[nodiscard]] static inline std::string toString(DeprecatedEnum val) {
   switch(val) {
   case DeprecatedEnum::A:
@@ -42,6 +43,7 @@
     return std::to_string(static_cast<int32_t>(val));
   }
 }
+#pragma clang diagnostic pop
 }  // namespace tests
 }  // namespace aidl
 }  // namespace android
@@ -50,8 +52,9 @@
 namespace internal {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc++17-extensions"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 template <>
-constexpr inline std::array<aidl::android::aidl::tests::DeprecatedEnum, 3> __attribute__((deprecated("test"))) enum_values<aidl::android::aidl::tests::DeprecatedEnum> = {
+constexpr inline std::array<aidl::android::aidl::tests::DeprecatedEnum, 3> enum_values<aidl::android::aidl::tests::DeprecatedEnum> = {
   aidl::android::aidl::tests::DeprecatedEnum::A,
   aidl::android::aidl::tests::DeprecatedEnum::B,
   aidl::android::aidl::tests::DeprecatedEnum::C,
diff --git a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/IntEnum.h b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/IntEnum.h
index 7d29fd4..d272eb3 100644
--- a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/IntEnum.h
+++ b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/IntEnum.h
@@ -19,6 +19,7 @@
   FOO = 1000,
   BAR = 2000,
   BAZ = 2001,
+  QUX __attribute__((deprecated("do not use this"))) = 2002,
 };
 
 }  // namespace tests
@@ -29,6 +30,8 @@
 namespace android {
 namespace aidl {
 namespace tests {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 [[nodiscard]] static inline std::string toString(IntEnum val) {
   switch(val) {
   case IntEnum::FOO:
@@ -37,10 +40,13 @@
     return "BAR";
   case IntEnum::BAZ:
     return "BAZ";
+  case IntEnum::QUX:
+    return "QUX";
   default:
     return std::to_string(static_cast<int32_t>(val));
   }
 }
+#pragma clang diagnostic pop
 }  // namespace tests
 }  // namespace aidl
 }  // namespace android
@@ -49,11 +55,13 @@
 namespace internal {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc++17-extensions"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 template <>
-constexpr inline std::array<aidl::android::aidl::tests::IntEnum, 3> enum_values<aidl::android::aidl::tests::IntEnum> = {
+constexpr inline std::array<aidl::android::aidl::tests::IntEnum, 4> enum_values<aidl::android::aidl::tests::IntEnum> = {
   aidl::android::aidl::tests::IntEnum::FOO,
   aidl::android::aidl::tests::IntEnum::BAR,
   aidl::android::aidl::tests::IntEnum::BAZ,
+  aidl::android::aidl::tests::IntEnum::QUX,
 };
 #pragma clang diagnostic pop
 }  // namespace internal
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/IntEnum.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/IntEnum.rs
index 5ff4d95..70e71dd 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/IntEnum.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/IntEnum.rs
@@ -3,10 +3,12 @@
 #![allow(non_upper_case_globals)]
 use binder::declare_binder_enum;
 declare_binder_enum! {
-  IntEnum : [i32; 3] {
+  IntEnum : [i32; 4] {
     FOO = 1000,
     BAR = 2000,
     BAZ = 2001,
+    #[deprecated = "do not use this"]
+    QUX = 2002,
   }
 }
 pub(crate) mod mangled {