C++/NDK backends reorder nested type decls.
In the following example, C is declared before B.
parcelabe A {
parcelabe B {
C c;
}
parcelable C {}
}
Otherwise, C++ compiler will complain about undefined symbols.
Still we can't define nested types with cyclic references because decl
order is not determined for C++/NDK backends.
Bug: 201376182
Test: golden_test.sh check
Test: aidl_unittests
Change-Id: I8340dc33e3f745aa51dca038af0ad55893c3aa05
diff --git a/aidl_language.h b/aidl_language.h
index 52fabf9..a920dab 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -1272,3 +1272,68 @@
T* AidlCast(AidlNode& node) {
return const_cast<T*>(AidlCast<T>(const_cast<const AidlNode&>(node)));
}
+
+template <typename AidlNodeType>
+vector<const AidlNodeType*> Collect(const AidlNode& root) {
+ vector<const AidlNodeType*> result;
+ std::function<void(const AidlNode&)> top_down = [&](const AidlNode& n) {
+ if (auto cast = AidlCast<AidlNodeType>(n); cast) {
+ result.push_back(cast);
+ }
+ n.TraverseChildren(top_down);
+ };
+ top_down(root);
+ return result;
+}
+
+template <typename VisitFn>
+bool TopologicalVisit(const vector<unique_ptr<AidlDefinedType>>& nested_types, VisitFn visit) {
+ // 1. Maps deeply nested types to one of nested_types
+ map<const AidlDefinedType*, const AidlDefinedType*> roots;
+ for (const auto& nested : nested_types) {
+ for (const auto& t : Collect<AidlDefinedType>(*nested)) {
+ roots[t] = nested.get();
+ }
+ }
+ // 2. Collect sibling types referenced within each nested type.
+ map<const AidlDefinedType*, vector<const AidlDefinedType*>> required_types;
+ for (const auto& nested : nested_types) {
+ for (const auto& t : Collect<AidlTypeSpecifier>(*nested)) {
+ if (auto defined_type = t->GetDefinedType(); defined_type) {
+ auto sibling = roots[defined_type];
+ if (sibling && sibling != nested.get()) {
+ required_types[nested.get()].push_back(sibling);
+ }
+ }
+ }
+ };
+ // 3. Run DFS
+ enum { NOT_STARTED = 0, STARTED = 1, FINISHED = 2 };
+ map<const AidlDefinedType*, int> visited;
+ std::function<bool(const AidlDefinedType&)> dfs = [&](const AidlDefinedType& type) {
+ if (visited[&type] == FINISHED) {
+ return true;
+ } else if (visited[&type] == STARTED) {
+ return false;
+ } else {
+ visited[&type] = STARTED;
+ // Visit every required dep first
+ for (const auto& dep_type : required_types[&type]) {
+ if (!dfs(*dep_type)) {
+ return false;
+ }
+ }
+ visited[&type] = FINISHED;
+ visit(type);
+ return true;
+ }
+ };
+
+ for (const auto& type : nested_types) {
+ if (!dfs(*type)) {
+ return false;
+ }
+ }
+
+ return true;
+}