nested types: GenerateHeaderIncludes()

Visitor-based function gathers all include files for a header with
nested types.

However GenerateHeader() doesn't support nested types yet. Upcoming
changes will make it to generate class decl for each nested type
recursively.

Bug: 182508839
Test: aidl_unittests
Test: tests/golden_test.sh check
Change-Id: I2bb6b160a6a99fef7576c4c22f10e6015f3dc5c0
diff --git a/aidl_language.h b/aidl_language.h
index 2f81522..f7c6d4b 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -1104,6 +1104,9 @@
 
   void TraverseChildren(std::function<void(const AidlNode&)> traverse) const override {
     AidlDefinedType::TraverseChildren(traverse);
+    if (backing_type_) {
+      traverse(*backing_type_);
+    }
     for (const auto& c : GetEnumerators()) {
       traverse(*c);
     }
diff --git a/aidl_to_cpp.cpp b/aidl_to_cpp.cpp
index 8aa6d1f..4ef185f 100644
--- a/aidl_to_cpp.cpp
+++ b/aidl_to_cpp.cpp
@@ -287,6 +287,7 @@
   return variable_name;
 }
 
+// Add includes for a type ref. Note that this is non-recursive.
 void AddHeaders(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
                 std::set<std::string>* headers) {
   AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type);
@@ -297,11 +298,6 @@
   if (isVector) {
     headers->insert("vector");
   }
-  if (type.IsGeneric()) {
-    for (const auto& parameter : type.GetTypeParameters()) {
-      AddHeaders(*parameter, typenames, headers);
-    }
-  }
   if (isNullable) {
     if (type.GetName() != "IBinder") {
       headers->insert("optional");
@@ -342,26 +338,32 @@
     return;
   }
 
-  auto definedType = typenames.TryGetDefinedType(type.GetName());
-  AIDL_FATAL_IF(definedType == nullptr, type) << "Unexpected type: " << type.GetName();
+  auto defined_type = typenames.TryGetDefinedType(type.GetName());
+  AIDL_FATAL_IF(defined_type == nullptr, type) << "Unexpected type: " << type.GetName();
 
-  if (definedType->AsInterface() != nullptr || definedType->AsStructuredParcelable() != nullptr ||
-      definedType->AsEnumDeclaration() != nullptr || definedType->AsUnionDeclaration() != nullptr) {
-    AddHeaders(*definedType, headers);
-  } else if (definedType->AsParcelable() != nullptr) {
-    const std::string cpp_header = definedType->AsParcelable()->GetCppHeader();
-    AIDL_FATAL_IF(cpp_header.empty(), definedType->AsParcelable())
-        << "Parcelable " << definedType->AsParcelable()->GetCanonicalName()
-        << " has no C++ header defined.";
-    headers->insert(cpp_header);
-  }
+  headers->insert(CppHeaderForType(*defined_type));
 }
 
-void AddHeaders(const AidlDefinedType& definedType, std::set<std::string>* headers) {
-  vector<string> name = definedType.GetSplitPackage();
-  name.push_back(definedType.GetName());
-  const std::string cpp_header = Join(name, '/') + ".h";
-  headers->insert(cpp_header);
+std::string CppHeaderForType(const AidlDefinedType& defined_type) {
+  // Unstructured parcelable should set its cpp_header. use it.
+  if (auto unstructured = AidlCast<AidlParcelable>(defined_type); unstructured) {
+    const std::string cpp_header = unstructured->GetCppHeader();
+    AIDL_FATAL_IF(cpp_header.empty(), unstructured)
+        << "Parcelable " << unstructured->GetCanonicalName() << " has no C++ header defined.";
+    return cpp_header;
+  }
+  // For a nested type, we need to include its top-most parent type's header.
+  const AidlDefinedType* toplevel = &defined_type;
+  for (auto parent = toplevel->GetParentType(); parent;) {
+    toplevel = parent;
+    parent = toplevel->GetParentType();
+  }
+  AIDL_FATAL_IF(toplevel->GetParentType() != nullptr, defined_type)
+      << "Can't find a top-level decl";
+
+  vector<string> name = toplevel->GetSplitPackage();
+  name.push_back(toplevel->GetName());
+  return Join(name, '/') + ".h";
 }
 
 }  // namespace cpp
diff --git a/aidl_to_cpp.h b/aidl_to_cpp.h
index f6974f5..620897f 100644
--- a/aidl_to_cpp.h
+++ b/aidl_to_cpp.h
@@ -61,7 +61,7 @@
 void AddHeaders(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
                 std::set<std::string>* headers);
 
-void AddHeaders(const AidlDefinedType& parcelable, std::set<std::string>* headers);
+std::string CppHeaderForType(const AidlDefinedType& defined_type);
 }  // namespace cpp
 }  // namespace aidl
 }  // namespace android
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index b650e97..ab01940 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -1665,6 +1665,23 @@
   }
 }
 
+TEST_F(AidlTest, HeaderForNestedTypeShouldPointToTopMostParent) {
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "interface IFoo {\n"
+      "  parcelable Result {}\n"
+      "}";
+  CaptureStderr();
+  auto foo = Parse(input_path, input, typenames_, Options::Language::CPP);
+  ASSERT_NE(nullptr, foo);
+  EXPECT_EQ(GetCapturedStderr(), "");
+
+  auto result = typenames_.ResolveTypename("p.IFoo.Result").defined_type;
+  ASSERT_NE(nullptr, result);
+  EXPECT_EQ("p/IFoo.h", cpp::CppHeaderForType(*result));
+}
+
 TEST_F(AidlTest, CppNameOf_GenericType) {
   const string input_path = "p/Wrapper.aidl";
   const string input = "package p; parcelable Wrapper<T> {}";
diff --git a/ast_cpp.cpp b/ast_cpp.cpp
index 39af24c..d490294 100644
--- a/ast_cpp.cpp
+++ b/ast_cpp.cpp
@@ -473,7 +473,9 @@
   for (const auto& include : include_list_) {
     to->Write("#include <%s>\n", include.c_str());
   }
-  to->Write("\n");
+  if (!include_list_.empty()) {
+    to->Write("\n");
+  }
 
   for (const auto& declaration : declarations_) {
     declaration->Write(to);
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index c7feb6a..526e94a 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -534,7 +534,7 @@
 }
 
 void BuildConstantDeclarations(const AidlDefinedType& type, const AidlTypenames& typenames,
-                               unique_ptr<ClassDecl>& cls, set<string>& includes) {
+                               unique_ptr<ClassDecl>& cls) {
   std::vector<std::unique_ptr<Declaration>> string_constants;
   unique_ptr<Enum> byte_constant_enum{new Enum{"", "int8_t", false}};
   unique_ptr<Enum> int_constant_enum{new Enum{"", "int32_t", false}};
@@ -572,8 +572,6 @@
     cls->AddPublic(std::move(long_constant_enum));
   }
   if (!string_constants.empty()) {
-    includes.insert(kString16Header);
-
     for (auto& string_constant : string_constants) {
       cls->AddPublic(std::move(string_constant));
     }
@@ -998,16 +996,6 @@
 
 unique_ptr<Document> BuildInterfaceHeader(const AidlTypenames& typenames,
                                           const AidlInterface& interface, const Options& options) {
-  set<string> includes = {kIBinderHeader, kIInterfaceHeader, kStatusHeader, kStrongPointerHeader};
-
-  for (const auto& method : interface.GetMethods()) {
-    for (const auto& argument : method->GetArguments()) {
-      AddHeaders(argument->GetType(), typenames, &includes);
-    }
-
-    AddHeaders(method->GetType(), typenames, &includes);
-  }
-
   const string i_name = ClassName(interface, ClassNames::INTERFACE);
   const string attribute = GetDeprecatedAttribute(interface);
   unique_ptr<ClassDecl> if_class{new ClassDecl{i_name, "::android::IInterface", {}, attribute}};
@@ -1028,11 +1016,7 @@
     if_class->AddPublic(unique_ptr<Declaration>(new LiteralDecl(code.str())));
   }
 
-  BuildConstantDeclarations(interface, typenames, if_class, includes);
-
-  if (options.GenTraces()) {
-    includes.insert(kTraceHeader);
-  }
+  BuildConstantDeclarations(interface, typenames, if_class);
 
   if (!interface.GetMethods().empty()) {
     for (const auto& method : interface.GetMethods()) {
@@ -1097,9 +1081,8 @@
       attribute,  // inherits the same attributes
   });
 
-  return unique_ptr<Document>{
-      new CppHeader{vector<string>(includes.begin(), includes.end()),
-                    NestInNamespaces(std::move(decls), interface.GetSplitPackage())}};
+  return unique_ptr<Document>(
+      new Document({}, NestInNamespaces(std::move(decls), interface.GetSplitPackage())));
 }
 
 string GetInitializer(const AidlTypenames& typenames, const AidlVariableDeclaration& variable) {
@@ -1254,19 +1237,12 @@
   unique_ptr<ClassDecl> parcel_class{
       new ClassDecl{parcel.GetName(), "::android::Parcelable", type_params, attribute}};
 
-  set<string> includes = {kStatusHeader, kParcelHeader, kString16Header};
-  AddTypeSpecificHeaders(parcel, includes);
-
-  for (const auto& variable : parcel.GetFields()) {
-    AddHeaders(variable->GetType(), typenames, &includes);
-  }
-
   string operator_code;
   GenerateParcelableComparisonOperators(*CodeWriter::ForString(&operator_code), parcel);
   parcel_class->AddPublic(std::make_unique<LiteralDecl>(operator_code));
 
   BuildParcelFields(*parcel_class, parcel, typenames);
-  BuildConstantDeclarations(parcel, typenames, parcel_class, includes);
+  BuildConstantDeclarations(parcel, typenames, parcel_class);
 
   if (parcel.IsVintfStability()) {
     parcel_class->AddPublic(std::unique_ptr<LiteralDecl>(
@@ -1291,20 +1267,12 @@
                                    parcel.GetCanonicalName().c_str()))));
 
   // toString() method
-  includes.insert("android/binder_to_string.h");
   string to_string;
   GenerateToString(*CodeWriter::ForString(&to_string), parcel);
   parcel_class->AddPublic(std::make_unique<LiteralDecl>(to_string));
 
-  auto decls = NestInNamespaces(std::move(parcel_class), parcel.GetSplitPackage());
-  // TODO(b/31559095) bionic on host should define this
-  if (parcel.AsUnionDeclaration()) {
-    decls.insert(decls.begin(),
-                 std::make_unique<LiteralDecl>(
-                     "#ifndef __BIONIC__\n#define __assert2(a,b,c,d) ((void)0)\n#endif\n\n"));
-  }
-  return unique_ptr<Document>{
-      new CppHeader{vector<string>(includes.begin(), includes.end()), std::move(decls)}};
+  return unique_ptr<Document>(
+      new Document({}, NestInNamespaces(std::move(parcel_class), parcel.GetSplitPackage())));
 }
 
 template <typename T>
@@ -1327,11 +1295,8 @@
   file_decls.push_back(std::move(read));
   file_decls.push_back(std::move(write));
 
-  set<string> includes = {};
-  AddHeaders(parcel, &includes);
-
   return unique_ptr<Document>{
-      new CppSource{vector<string>(includes.begin(), includes.end()),
+      new CppSource{vector<string>{cpp::CppHeaderForType(parcel)},
                     NestInNamespaces(std::move(file_decls), parcel.GetSplitPackage())}};
 }
 
@@ -1375,13 +1340,6 @@
         enumerator->ValueString(enum_decl.GetBackingType(), ConstantValueDecorator));
   }
 
-  std::set<std::string> includes = {
-      "array",
-      "binder/Enums.h",
-      "string",
-  };
-  AddHeaders(enum_decl.GetBackingType(), typenames, &includes);
-
   std::vector<std::unique_ptr<Declaration>> decls1;
   decls1.push_back(std::move(generated_enum));
   decls1.push_back(std::make_unique<LiteralDecl>(GenerateEnumToString(typenames, enum_decl)));
@@ -1389,10 +1347,9 @@
   std::vector<std::unique_ptr<Declaration>> decls2;
   decls2.push_back(std::make_unique<LiteralDecl>(GenerateEnumValues(enum_decl, {""})));
 
-  return unique_ptr<Document>{
-      new CppHeader{vector<string>(includes.begin(), includes.end()),
-                    Append(NestInNamespaces(std::move(decls1), enum_decl.GetSplitPackage()),
-                           NestInNamespaces(std::move(decls2), {"android", "internal"}))}};
+  return unique_ptr<Document>(
+      new Document({}, Append(NestInNamespaces(std::move(decls1), enum_decl.GetSplitPackage()),
+                              NestInNamespaces(std::move(decls2), {"android", "internal"}))));
 }
 
 }  // namespace internals
@@ -1424,9 +1381,77 @@
   return true;
 }
 
+// Collect all includes for the type's header. Nested types are visited as well via VisitTopDown.
+void GenerateHeaderIncludes(CodeWriter& out, const AidlDefinedType& defined_type,
+                            const AidlTypenames& typenames, const Options& options) {
+  struct Visitor : AidlVisitor {
+    const AidlTypenames& typenames;
+    const Options& options;
+    std::set<std::string> includes;
+    Visitor(const AidlTypenames& typenames, const Options& options)
+        : typenames(typenames), options(options) {}
+
+    // Collect includes for each type reference including built-in type
+    void Visit(const AidlTypeSpecifier& type) override {
+      cpp::AddHeaders(type, typenames, &includes);
+    }
+
+    // Collect implementation-specific includes for each type definition
+    void Visit(const AidlInterface&) override {
+      includes.insert(kIBinderHeader);        // IBinder
+      includes.insert(kIInterfaceHeader);     // IInterface
+      includes.insert(kStatusHeader);         // Status
+      includes.insert(kStrongPointerHeader);  // sp<>
+
+      if (options.GenTraces()) {
+        includes.insert(kTraceHeader);
+      }
+    }
+
+    void Visit(const AidlStructuredParcelable&) override {
+      AddParcelableCommonHeaders();
+      includes.insert("tuple");  // std::tie in comparison operators
+    }
+
+    void Visit(const AidlUnionDecl&) override {
+      AddParcelableCommonHeaders();
+      includes.insert(std::begin(UnionWriter::headers), std::end(UnionWriter::headers));
+    }
+
+    void Visit(const AidlEnumDeclaration&) override {
+      includes.insert("array");           // used in enum_values
+      includes.insert("binder/Enums.h");  // provides enum_range
+      includes.insert("string");          // toString() returns std::string
+    }
+
+    void AddParcelableCommonHeaders() {
+      includes.insert(kParcelHeader);                 // Parcel in readFromParcel/writeToParcel
+      includes.insert(kStatusHeader);                 // Status
+      includes.insert(kString16Header);               // String16 in getParcelableDescriptor
+      includes.insert("android/binder_to_string.h");  // toString()
+    }
+  } v(typenames, options);
+  VisitTopDown(v, defined_type);
+
+  for (const auto& path : v.includes) {
+    out << "#include <" << path << ">\n";
+  }
+  out << "\n";
+  if (v.includes.count("cassert")) {
+    // TODO(b/31559095) bionic on host should define __assert2
+    out << "#ifndef __BIONIC__\n#define __assert2(a,b,c,d) ((void)0)\n#endif\n\n";
+  }
+}
+
 // TODO(b/182508839) should emit nested types recursively
 void GenerateHeader(CodeWriter& out, const AidlDefinedType& defined_type,
                     const AidlTypenames& typenames, const Options& options) {
+  if (auto parcelable = AidlCast<AidlParcelable>(defined_type); parcelable) {
+    out << "#error TODO(b/111362593) parcelables do not have headers";
+    return;
+  }
+  out << "#pragma once\n\n";
+  GenerateHeaderIncludes(out, defined_type, typenames, options);
   if (auto iface = AidlCast<AidlInterface>(defined_type); iface) {
     BuildInterfaceHeader(typenames, *iface, options)->Write(&out);
   } else if (auto parcelable = AidlCast<AidlStructuredParcelable>(defined_type); parcelable) {
@@ -1441,8 +1466,6 @@
     }
   } else if (auto enum_decl = AidlCast<AidlEnumDeclaration>(defined_type); enum_decl) {
     BuildEnumHeader(typenames, *enum_decl)->Write(&out);
-  } else if (auto parcelable = AidlCast<AidlParcelable>(defined_type); parcelable) {
-    out << "#error TODO(b/111362593) parcelables do not have headers";
   } else {
     AIDL_FATAL(defined_type) << "Unrecognized type sent for CPP generation.";
   }