Parsing nested types.

The grammar supports nested types now. preprocess/dumpapi dumps nested
types.

  interface IFoo {
    enum Type { FOO, BAR }
    parcelable Result { ... }
    Result foo(Type type);
  }

Backend support is not supported yet.

Bug: 182508839
Test: aidl_unittests
Change-Id: Ic7d1bc8aec788b65de85caad2a813a52fb2cfc5e
diff --git a/aidl.cpp b/aidl.cpp
index e90fae1..882aef6 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -688,6 +688,12 @@
     for (const auto& defined_type : typenames.MainDocument().DefinedTypes()) {
       AIDL_FATAL_IF(defined_type == nullptr, input_file);
 
+      // TODO(b/182508839) add backend support for nested types
+      if (!defined_type->GetNestedTypes().empty()) {
+        AIDL_ERROR(defined_type) << "Nested types are not supported yet.";
+        return false;
+      }
+
       string output_file_name = options.OutputFile();
       // if needed, generate the output file name from the base folder
       if (output_file_name.empty() && !options.OutputDir().empty()) {
diff --git a/aidl_dumpapi.cpp b/aidl_dumpapi.cpp
index ce5a1f7..7d3f19d 100644
--- a/aidl_dumpapi.cpp
+++ b/aidl_dumpapi.cpp
@@ -56,6 +56,9 @@
   for (const auto& constdecl : dt.GetConstantDeclarations()) {
     constdecl->DispatchVisit(*this);
   }
+  for (const auto& nested : dt.GetNestedTypes()) {
+    nested->DispatchVisit(*this);
+  }
 }
 
 // Dumps comment only if its has meaningful tags.
diff --git a/aidl_language.cpp b/aidl_language.cpp
index a0cad71..b1c4a12 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -882,7 +882,7 @@
 }
 
 AidlMember::AidlMember(const AidlLocation& location, const Comments& comments)
-    : AidlCommentable(location, comments) {}
+    : AidlAnnotatable(location, comments) {}
 
 AidlConstantDeclaration::AidlConstantDeclaration(const AidlLocation& location,
                                                  AidlTypeSpecifier* type, const std::string& name,
@@ -962,7 +962,7 @@
 AidlDefinedType::AidlDefinedType(const AidlLocation& location, const std::string& name,
                                  const Comments& comments, const std::string& package,
                                  std::vector<std::unique_ptr<AidlMember>>* members)
-    : AidlAnnotatable(location, comments), AidlScope(this), name_(name), package_(package) {
+    : AidlMember(location, comments), AidlScope(this), name_(name), package_(package) {
   // adjust name/package when name is fully qualified (for preprocessed files)
   if (package_.empty() && name_.find('.') != std::string::npos) {
     // Note that this logic is absolutely wrong.  Given a parcelable
@@ -984,6 +984,9 @@
         variables_.emplace_back(variable);
       } else if (auto method = AidlCast<AidlMethod>(*m); method) {
         methods_.emplace_back(method);
+      } else if (auto type = AidlCast<AidlDefinedType>(*m); type) {
+        type->SetEnclosingScope(this);
+        types_.emplace_back(type);
       } else {
         AIDL_FATAL(*m) << "Unknown member type.";
       }
@@ -1007,12 +1010,39 @@
   if (package_.empty()) {
     return GetName();
   }
+  if (auto parent = GetParentType(); parent) {
+    return parent->GetCanonicalName() + "." + GetName();
+  }
   return GetPackage() + "." + GetName();
 }
 
 bool AidlDefinedType::CheckValidWithMembers(const AidlTypenames& typenames) const {
   bool success = true;
 
+  for (const auto& t : GetNestedTypes()) {
+    success = success && t->CheckValid(typenames);
+  }
+
+  std::set<std::string> nested_type_names;
+  for (const auto& t : GetNestedTypes()) {
+    bool duplicated = !nested_type_names.emplace(t->GetName()).second;
+    if (duplicated) {
+      AIDL_ERROR(t) << "Redefinition of '" << t->GetName() << "'.";
+      success = false;
+    }
+    // nested type can't have a parent name
+    if (t->GetName() == GetName()) {
+      AIDL_ERROR(t) << "Nested type '" << GetName() << "' has the same name as its parent.";
+      success = false;
+    }
+    // For now we don't allow "interface" to be nested
+    if (AidlCast<AidlInterface>(*t)) {
+      AIDL_ERROR(t) << "'" << t->GetName()
+                    << "' is nested. Interfaces should be at the root scope.";
+      return false;
+    }
+  }
+
   for (const auto& v : GetFields()) {
     const bool field_valid = v->CheckValid(typenames);
     success = success && field_valid;
@@ -1066,23 +1096,45 @@
   return success;
 }
 
+const AidlDefinedType* AidlDefinedType::GetParentType() const {
+  AIDL_FATAL_IF(GetEnclosingScope() == nullptr, this) << "Scope is not set.";
+  return AidlCast<AidlDefinedType>(GetEnclosingScope()->GetNode());
+}
+
+// Resolve `name` in the current scope. If not found, delegate to the parent
 std::string AidlDefinedType::ResolveName(const std::string& name) const {
-  // TODO(b/182508839): resolve with nested types when we support nested types
-  //
-  // For example, in the following (the syntax is TBD), t1's Type is x.Foo.Bar.Type
-  // while t2's Type is y.Type.
-  //
+  // For example, in the following, t1's type Baz means x.Foo.Bar.Baz
+  // while t2's type is y.Baz.
   // package x;
-  // import y.Type;
+  // import y.Baz;
   // parcelable Foo {
   //   parcelable Bar {
-  //     enum Type { Type1, Type2 }
-  //     Type t1;
+  //     enum Baz { ... }
+  //     Baz t1; // -> should be x.Foo.Bar.Baz
   //   }
-  //   Type t2;
+  //   Baz t2; // -> should be y.Baz
+  //   Bar.Baz t3; // -> should be x.Foo.Bar.Baz
   // }
   AIDL_FATAL_IF(!GetEnclosingScope(), this)
       << "Type should have an enclosing scope.(e.g. AidlDocument)";
+  if (AidlTypenames::IsBuiltinTypename(name)) {
+    return name;
+  }
+
+  const auto first_dot = name.find_first_of('.');
+  // For "Outer.Inner", we look up "Outer" in the import list.
+  const std::string class_name =
+      (first_dot == std::string::npos) ? name : name.substr(0, first_dot);
+  // Keep ".Inner", to make a fully-qualified name
+  const std::string nested_type = (first_dot == std::string::npos) ? "" : name.substr(first_dot);
+
+  // check if it is a nested type
+  for (const auto& type : GetNestedTypes()) {
+    if (type->GetName() == class_name) {
+      return type->GetCanonicalName() + nested_type;
+    }
+  }
+
   return GetEnclosingScope()->ResolveName(name);
 }
 
diff --git a/aidl_language.h b/aidl_language.h
index 59bd1cd..2f81522 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -458,7 +458,7 @@
 // Returns the universal value unaltered.
 std::string AidlConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value);
 
-class AidlMember : public AidlCommentable {
+class AidlMember : public AidlAnnotatable {
  public:
   AidlMember(const AidlLocation& location, const Comments& comments);
   virtual ~AidlMember() = default;
@@ -894,7 +894,7 @@
 
 // AidlDefinedType represents either an interface, parcelable, or enum that is
 // defined in the source file.
-class AidlDefinedType : public AidlAnnotatable, public AidlScope {
+class AidlDefinedType : public AidlMember, public AidlScope {
  public:
   AidlDefinedType(const AidlLocation& location, const std::string& name, const Comments& comments,
                   const std::string& package, std::vector<std::unique_ptr<AidlMember>>* members);
@@ -963,7 +963,8 @@
     return const_cast<AidlParcelable*>(
         const_cast<const AidlDefinedType*>(this)->AsUnstructuredParcelable());
   }
-
+  const AidlDefinedType* GetParentType() const;
+  const std::vector<std::unique_ptr<AidlDefinedType>>& GetNestedTypes() const { return types_; }
   const std::vector<std::unique_ptr<AidlVariableDeclaration>>& GetFields() const {
     return variables_;
   }
@@ -992,6 +993,7 @@
   std::vector<std::unique_ptr<AidlVariableDeclaration>> variables_;
   std::vector<std::unique_ptr<AidlConstantDeclaration>> constants_;
   std::vector<std::unique_ptr<AidlMethod>> methods_;
+  std::vector<std::unique_ptr<AidlDefinedType>> types_;
   std::vector<const AidlMember*> members_;  // keep members in order of appearance.
 };
 
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index b9e1d0c..e37fc3f 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -347,6 +347,10 @@
     $1->emplace_back($2);
     $$ = $1;
   }
+ | parcelable_members decl {
+    $1->emplace_back($2);
+    $$ = $1;
+  }
  | parcelable_members error ';' {
     ps->AddError();
     $$ = $1;
@@ -398,6 +402,8 @@
   { $1->push_back(std::unique_ptr<AidlMember>($2)); $$ = $1; }
  | interface_members constant_decl
   { $1->push_back(std::unique_ptr<AidlMember>($2)); $$ = $1; }
+ | interface_members decl
+  { $1->push_back(std::unique_ptr<AidlMember>($2)); $$ = $1; }
  | interface_members error ';' {
     ps->AddError();
     $$ = $1;
diff --git a/aidl_typenames.cpp b/aidl_typenames.cpp
index 13d7bcf..d1ccfcb 100644
--- a/aidl_typenames.cpp
+++ b/aidl_typenames.cpp
@@ -127,36 +127,50 @@
   // Add types in two steps to avoid adding a type while the doc is rejected.
   // 1. filter types to add
   // 2. add types
-  for (const auto& type : doc->DefinedTypes()) {
-    if (IsBuiltinTypename(type->GetName())) {
-      // ParcelFileDescriptor is treated as a built-in type, but it's also in the framework.aidl.
-      // So aidl should ignore built-in types in framework.aidl to prevent duplication.
-      // (b/130899491)
-      if (is_preprocessed) {
-        continue;
-      }
-      // HasValidNameComponents handles name conflicts with built-in types
-    }
 
-    if (auto prev_definition = defined_types_.find(type->GetCanonicalName());
-        prev_definition != defined_types_.end()) {
-      // Skip duplicate type in preprocessed document
-      if (is_preprocessed) {
-        continue;
+  std::function<bool(const std::vector<std::unique_ptr<AidlDefinedType>>&)> collect_types_to_add;
+  collect_types_to_add = [&](auto& types) {
+    for (const auto& type : types) {
+      if (IsBuiltinTypename(type->GetName())) {
+        // ParcelFileDescriptor is treated as a built-in type, but it's also in the framework.aidl.
+        // So aidl should ignore built-in types in framework.aidl to prevent duplication.
+        // (b/130899491)
+        if (is_preprocessed) {
+          continue;
+        }
+        // HasValidNameComponents handles name conflicts with built-in types
       }
-      // Overwrite duplicate type which is already added via preprocessed with a new one
-      if (!prev_definition->second->GetDocument().IsPreprocessed()) {
-        AIDL_ERROR(type) << "redefinition: " << type->GetCanonicalName() << " is defined "
-                         << prev_definition->second->GetLocation();
+
+      if (auto prev_definition = defined_types_.find(type->GetCanonicalName());
+          prev_definition != defined_types_.end()) {
+        // Skip duplicate type in preprocessed document
+        if (is_preprocessed) {
+          continue;
+        }
+        // Overwrite duplicate type which is already added via preprocessed with a new one
+        if (!prev_definition->second->GetDocument().IsPreprocessed()) {
+          AIDL_ERROR(type) << "redefinition: " << type->GetCanonicalName() << " is defined "
+                           << prev_definition->second->GetLocation();
+          return false;
+        }
+      }
+
+      if (!HasValidNameComponents(*type)) {
+        return false;
+      }
+
+      types_to_add.push_back(type.get());
+
+      // recursively check nested types
+      if (!collect_types_to_add(type->GetNestedTypes())) {
         return false;
       }
     }
+    return true;
+  };
 
-    if (!HasValidNameComponents(*type)) {
-      return false;
-    }
-
-    types_to_add.push_back(type.get());
+  if (!collect_types_to_add(doc->DefinedTypes())) {
+    return false;
   }
 
   for (const auto& type : types_to_add) {
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 25437f9..b650e97 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -25,6 +25,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <variant>
 #include <vector>
 
 #include "aidl_checkapi.h"
@@ -45,6 +46,7 @@
 using std::set;
 using std::string;
 using std::unique_ptr;
+using std::variant;
 using std::vector;
 using testing::HasSubstr;
 using testing::TestParamInfo;
@@ -1414,7 +1416,7 @@
   EXPECT_EQ("-1", cpp_constants[0]->ValueString(cpp::ConstantValueDecorator));
 }
 
-TEST_P(AidlTest, UnderstandsNestedParcelables) {
+TEST_P(AidlTest, UnderstandsNestedUnstructuredParcelables) {
   io_delegate_.SetFileContents(
       "p/Outer.aidl",
       "package p; parcelable Outer.Inner cpp_header \"baz/header\";");
@@ -1432,7 +1434,7 @@
   EXPECT_EQ("::p::Outer::Inner", cpp::CppNameOf(nested_type, typenames_));
 }
 
-TEST_P(AidlTest, UnderstandsNestedParcelablesWithoutImports) {
+TEST_P(AidlTest, UnderstandsNestedUnstructuredParcelablesWithoutImports) {
   io_delegate_.SetFileContents("p/Outer.aidl",
                                "package p; parcelable Outer.Inner cpp_header \"baz/header\";");
   import_paths_.emplace("");
@@ -1448,6 +1450,221 @@
   EXPECT_EQ("::p::Outer::Inner", cpp::CppNameOf(nested_type, typenames_));
 }
 
+TEST_F(AidlTest, UnderstandsNestedTypes) {
+  io_delegate_.SetFileContents("p/IOuter.aidl",
+                               "package p;\n"
+                               "interface IOuter {\n"
+                               "  parcelable Inner {}\n"
+                               "}");
+  import_paths_.emplace("");
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "import p.IOuter;\n"
+      "interface IFoo {\n"
+      "  IOuter.Inner get();\n"
+      "}";
+  CaptureStderr();
+  EXPECT_NE(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_EQ(GetCapturedStderr(), "");
+
+  EXPECT_TRUE(typenames_.ResolveTypename("p.IOuter.Inner").is_resolved);
+  // C++ uses "::" instead of "." to refer to a inner class.
+  AidlTypeSpecifier nested_type(AIDL_LOCATION_HERE, "p.IOuter.Inner", false, nullptr, {});
+  EXPECT_EQ("::p::IOuter::Inner", cpp::CppNameOf(nested_type, typenames_));
+}
+
+TEST_F(AidlTest, UnderstandsNestedTypesViaFullyQualifiedName) {
+  io_delegate_.SetFileContents("p/IOuter.aidl",
+                               "package p;\n"
+                               "interface IOuter {\n"
+                               "  parcelable Inner {}\n"
+                               "}");
+  import_paths_.emplace("");
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "interface IFoo {\n"
+      "  p.IOuter.Inner get();\n"
+      "}";
+  CaptureStderr();
+  EXPECT_NE(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_EQ(GetCapturedStderr(), "");
+
+  EXPECT_TRUE(typenames_.ResolveTypename("p.IOuter.Inner").is_resolved);
+}
+
+TEST_F(AidlTest, UnderstandsNestedTypesViaFullyQualifiedImport) {
+  io_delegate_.SetFileContents("p/IOuter.aidl",
+                               "package p;\n"
+                               "interface IOuter {\n"
+                               "  parcelable Inner {}\n"
+                               "}");
+  import_paths_.emplace("");
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "import p.IOuter.Inner;"
+      "interface IFoo {\n"
+      "  Inner get();\n"
+      "}";
+  CaptureStderr();
+  EXPECT_NE(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_EQ(GetCapturedStderr(), "");
+
+  EXPECT_TRUE(typenames_.ResolveTypename("p.IOuter.Inner").is_resolved);
+}
+
+TEST_F(AidlTest, UnderstandsNestedTypesInTheSameScope) {
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "interface IFoo {\n"
+      "  parcelable Result {}\n"
+      "  Result get();\n"
+      "}";
+  CaptureStderr();
+  EXPECT_NE(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_EQ(GetCapturedStderr(), "");
+
+  EXPECT_TRUE(typenames_.ResolveTypename("p.IFoo.Result").is_resolved);
+}
+
+// Finding the type of nested named member.
+struct TypeFinder : AidlVisitor {
+  string name;
+  const AidlTypeSpecifier* type = nullptr;
+  TypeFinder(std::string name) : name(name) {}
+  void Visit(const AidlVariableDeclaration& v) override {
+    if (v.GetName() == name) {
+      type = &v.GetType();
+    }
+  }
+  void Visit(const AidlMethod& m) override {
+    if (m.GetName() == name) {
+      type = &m.GetType();
+    }
+  }
+  static string Get(const AidlDefinedType& type, const string& name) {
+    TypeFinder v(name);
+    VisitTopDown(v, type);
+    return v.type ? v.type->Signature() : "(null)";
+  };
+};
+
+TEST_F(AidlTest, UnderstandsNestedTypesViaQualifiedInTheSameScope) {
+  io_delegate_.SetFileContents("q/IBar.aidl",
+                               "package q;\n"
+                               "interface IBar {\n"
+                               "  parcelable Baz {}\n"
+                               "}");
+  import_paths_.emplace("");
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "import q.IBar;\n"
+      "interface IFoo {\n"
+      "  parcelable Nested {\n"
+      "    Baz t1;\n"
+      "  }\n"
+      "  parcelable Baz { }\n"
+      "  IBar.Baz t2();\n"
+      "  Baz t3();\n"
+      "}";
+  CaptureStderr();
+  auto foo = Parse(input_path, input, typenames_, Options::Language::CPP);
+  EXPECT_EQ(GetCapturedStderr(), "");
+  ASSERT_NE(nullptr, foo);
+
+  EXPECT_EQ(TypeFinder::Get(*foo, "t1"), "p.IFoo.Baz");
+  EXPECT_EQ(TypeFinder::Get(*foo, "t2"), "q.IBar.Baz");
+  EXPECT_EQ(TypeFinder::Get(*foo, "t3"), "p.IFoo.Baz");
+}
+
+TEST_F(AidlTest, RejectsNestedTypesWithParentsName) {
+  const string input_path = "p/Foo.aidl";
+  const string input =
+      "package p;\n"
+      "parcelable Foo {\n"
+      "  parcelable Foo {}\n"
+      "}";
+  CaptureStderr();
+  EXPECT_EQ(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_THAT(GetCapturedStderr(), HasSubstr("Nested type 'Foo' has the same name as its parent."));
+}
+
+TEST_F(AidlTest, RejectsInterfaceAsNestedTypes) {
+  const string input_path = "p/IFoo.aidl";
+  const string input =
+      "package p;\n"
+      "interface IFoo {\n"
+      "  interface ICallback { void done(); }\n"
+      "  void doTask(ICallback cb);\n"
+      "}";
+  CaptureStderr();
+  EXPECT_EQ(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_THAT(GetCapturedStderr(), HasSubstr("Interfaces should be at the root scope"));
+}
+
+TEST_F(AidlTest, RejectsNestedTypesWithDuplicateNames) {
+  const string input_path = "p/Foo.aidl";
+  const string input =
+      "package p;\n"
+      "interface Foo {\n"
+      "  parcelable Bar {}\n"
+      "  parcelable Bar {}\n"
+      "}";
+  CaptureStderr();
+  EXPECT_EQ(nullptr, Parse(input_path, input, typenames_, Options::Language::CPP));
+  EXPECT_THAT(GetCapturedStderr(), HasSubstr("Redefinition of 'Bar'"));
+}
+
+TEST_F(AidlTest, TypeResolutionWithMultipleLevelsOfNesting) {
+  struct Failure {
+    string err;
+  };
+  struct TestCase {
+    string type;
+    variant<string, Failure> expected;  // success<0> or failure<1>
+  };
+  vector<TestCase> cases = {
+      {"foo.A", "foo.A"},
+      {"foo.A.B", "foo.A.B"},
+      {"@nullable(heap=true) A", "foo.A.B.A"},
+      // In the scope of foo.A.B.A, B is resolved to A.B.A.B first.
+      {"B.A", Failure{"Failed to resolve 'B.A'"}},
+      {"B", "foo.A.B.A.B"},
+      {"A.B", "foo.A.B.A.B"},
+  };
+  const string input_path = "foo/A.aidl";
+  for (auto& [type, expected] : cases) {
+    AidlTypenames typenames;
+    // clang-format off
+    const string input =
+        "package foo;\n"
+        "parcelable A {\n"
+        "  parcelable B {\n"
+        "    parcelable A {\n"
+        "      parcelable B {\n"
+        "      }\n"
+        "      " + type + " m;\n"
+        "    }\n"
+        "  }\n"
+        "}";
+    // clang-format on
+    CaptureStderr();
+    auto foo = Parse(input_path, input, typenames, Options::Language::CPP);
+    if (auto failure = std::get_if<Failure>(&expected); failure) {
+      ASSERT_EQ(nullptr, foo);
+      EXPECT_THAT(GetCapturedStderr(), HasSubstr(failure->err));
+    } else {
+      EXPECT_EQ(GetCapturedStderr(), "");
+      ASSERT_NE(nullptr, foo);
+      EXPECT_EQ(TypeFinder::Get(*foo, "m"), std::get<string>(expected));
+    }
+  }
+}
+
 TEST_F(AidlTest, CppNameOf_GenericType) {
   const string input_path = "p/Wrapper.aidl";
   const string input = "package p; parcelable Wrapper<T> {}";
diff --git a/preprocess.cpp b/preprocess.cpp
index 2594ba6..b332f2e 100644
--- a/preprocess.cpp
+++ b/preprocess.cpp
@@ -27,7 +27,7 @@
 
 namespace {
 // PreprocessVisitor emits
-// - type including comments(hide/deprecated) and annotations
+// - types including comments(hide/deprecated) and annotations
 // - constant delcarations for interface/parcelable/unions
 // - enumerators for enums
 struct PreprocessVisitor : AidlVisitor {
@@ -37,7 +37,12 @@
   void DumpType(const AidlDefinedType& dt, const string& type) {
     DumpComments(dt);
     DumpAnnotations(dt);
-    out << type << " " << dt.GetCanonicalName();
+    // Top-level definition emits canonical name while nested type emits "name" only.
+    if (dt.GetParentType()) {
+      out << type << " " << dt.GetName();
+    } else {
+      out << type << " " << dt.GetCanonicalName();
+    }
     if (auto generic_type = dt.AsParameterizable(); generic_type && generic_type->IsGeneric()) {
       out << "<" << Join(generic_type->GetTypeParameters(), ", ") << ">";
     }
@@ -48,6 +53,9 @@
     for (const auto& constdecl : dt.GetConstantDeclarations()) {
       constdecl->DispatchVisit(*this);
     }
+    for (const auto& nested : dt.GetNestedTypes()) {
+      nested->DispatchVisit(*this);
+    }
     out.Dedent();
     out << "}\n";
   }