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_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);
}