cpp: handle generic type-parameters before @nullable

CppNameOf() should handle type-parameters first before applying
@nullable.

Bug: 188237977
Test: aidl_unittests
Change-Id: Ia5e2c7d6f8935646049110559cb46620dad0cd95
diff --git a/aidl_to_cpp.cpp b/aidl_to_cpp.cpp
index 40552c8..e7125f9 100644
--- a/aidl_to_cpp.cpp
+++ b/aidl_to_cpp.cpp
@@ -186,8 +186,15 @@
   if (definedType != nullptr && definedType->AsInterface() != nullptr) {
     return "::android::sp<" + GetRawCppName(type) + ">";
   }
-
-  return WrapIfNullable(GetRawCppName(type), raw_type, typenames);
+  auto cpp_name = GetRawCppName(type);
+  if (type.IsGeneric()) {
+    std::vector<std::string> type_params;
+    for (const auto& parameter : type.GetTypeParameters()) {
+      type_params.push_back(CppNameOf(*parameter, typenames));
+    }
+    cpp_name += "<" + base::Join(type_params, ", ") + ">";
+  }
+  return WrapIfNullable(cpp_name, raw_type, typenames);
 }
 }  // namespace
 std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) {
@@ -223,13 +230,6 @@
       return "::std::optional<::std::vector<" + cpp_name + ">>";
     }
     return "::std::vector<" + cpp_name + ">";
-  } else if (type.IsGeneric()) {
-    std::vector<std::string> type_params;
-    for (const auto& parameter : type.GetTypeParameters()) {
-      type_params.push_back(CppNameOf(*parameter, typenames));
-    }
-    return StringPrintf("%s<%s>", GetCppName(type, typenames).c_str(),
-                        base::Join(type_params, ", ").c_str());
   }
   return GetCppName(type, typenames);
 }
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index c3c04df..4113d3a 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -1180,6 +1180,62 @@
   EXPECT_EQ("::p::Outer::Inner", cpp::CppNameOf(nested_type, typenames_));
 }
 
+TEST_F(AidlTest, CppNameOf_GenericType) {
+  io_delegate_.SetFileContents("p/Wrapper.aidl", "package p; parcelable Wrapper<T> { T wrapped; }");
+  import_paths_.emplace("");
+  // Since we don't support compilation of Wrapper directly (due to "T" reference),
+  // prepare Holder so that Wrapper gets parsed into AidlTypenames
+  const string input_path = "p/Holder.aidl";
+  const string input =
+      "package p; import p.Wrapper; parcelable Holder {\n"
+      "  @nullable Wrapper<String> value;\n"
+      "}";
+
+  auto parse_result = Parse(input_path, input, typenames_, Options::Language::CPP);
+  EXPECT_NE(nullptr, parse_result);
+
+  auto type = [](std::string name, auto&&... type_params) -> std::unique_ptr<AidlTypeSpecifier> {
+    auto params = new std::vector<std::unique_ptr<AidlTypeSpecifier>>;
+    (..., params->emplace_back(std::move(type_params)));
+    return std::make_unique<AidlTypeSpecifier>(AIDL_LOCATION_HERE, name, false, params, Comments{});
+  };
+
+  auto set_nullable = [](std::unique_ptr<AidlTypeSpecifier>&& type) {
+    std::vector<AidlAnnotation> annotations;
+    annotations.emplace_back(*AidlAnnotation::Parse(AIDL_LOCATION_HERE, "nullable", nullptr, {}));
+    type->Annotate(std::move(annotations));
+    return std::move(type);
+  };
+
+  auto set_array = [](std::unique_ptr<AidlTypeSpecifier>&& type) {
+    (void)type->SetArray();
+    return std::move(type);
+  };
+
+  auto w = type("p.Wrapper", type("String"));
+  EXPECT_EQ("::p::Wrapper<::android::String16>", cpp::CppNameOf(*w, typenames_));
+
+  auto nullable_w = set_nullable(type("p.Wrapper", type("String")));
+  EXPECT_EQ("::std::optional<::p::Wrapper<::android::String16>>",
+            cpp::CppNameOf(*nullable_w, typenames_));
+
+  auto array_w = set_array(type("p.Wrapper", type("String")));
+  EXPECT_EQ("::std::vector<::p::Wrapper<::android::String16>>",
+            cpp::CppNameOf(*array_w, typenames_));
+
+  auto nullable_array_w = set_nullable(set_array(type("p.Wrapper", type("String"))));
+  EXPECT_EQ("::std::optional<::std::vector<::std::optional<::p::Wrapper<::android::String16>>>>",
+            cpp::CppNameOf(*nullable_array_w, typenames_));
+
+  auto list_w = type("List", type("p.Wrapper", type("String")));
+  EXPECT_EQ("::std::vector<::p::Wrapper<::android::String16>>",
+            cpp::CppNameOf(*list_w, typenames_));
+
+  auto nullable_list_w = set_nullable(type("List", type("p.Wrapper", type("String"))));
+  EXPECT_EQ("::std::optional<::std::vector<::std::optional<::p::Wrapper<::android::String16>>>>",
+            cpp::CppNameOf(*nullable_list_w, typenames_));
+}
+
 TEST_P(AidlTest, UnderstandsNativeParcelables) {
   io_delegate_.SetFileContents(
       "p/Bar.aidl",