const-ref: support recursive references

Referenced constant expression can also refer another constant
expressions.

  parcelable P {
    const int A = B + 1;
    const int B = C + 1;
    const int C = 1;
  }

This works with imported types.

  parcelable P { const int A = Q.A + 1; }
  parcelable Q { const int A = 1; }

Using this, "auto-fill" of enums got simplified.

  enum E { A, B } == enum E { A = 0, B = A + 1 }

Note that circular references are not supported.

  parcelable P { const int A = A + 1; } // error

Bug: 142893595
Bug: 174877216
Test: aidl_unittests
Change-Id: Ib187ec47c0184effd64568a9a3d57a2adf5aa4f4
diff --git a/parser.cpp b/parser.cpp
index b5053b6..15faed5 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -61,55 +61,110 @@
   }
 }
 
-bool Parser::Resolve() {
+class ConstantReferenceResolver : public AidlConstantValue::Visitor {
+ public:
+  ConstantReferenceResolver(const AidlDefinedType* scope, const AidlTypenames& typenames,
+                            TypeResolver& resolver, bool* success)
+      : scope_(scope), typenames_(typenames), resolver_(resolver), success_(success) {}
+  void Visit(AidlConstantValue&) override {}
+  void Visit(AidlUnaryConstExpression&) override {}
+  void Visit(AidlBinaryConstExpression&) override {}
+  void Visit(AidlConstantReference& v) override {
+    if (IsCircularReference(&v)) {
+      *success_ = false;
+      return;
+    }
+
+    // when <type> is missing, we use a scope type
+    if (!v.GetRefType()) {
+      v.SetRefType(std::make_unique<AidlTypeSpecifier>(v.GetLocation(), scope_->GetCanonicalName(),
+                                                       false, nullptr, ""));
+    }
+    if (!v.GetRefType()->IsResolved()) {
+      if (!resolver_(typenames_.GetDocumentFor(scope_), v.GetRefType().get())) {
+        AIDL_ERROR(v.GetRefType()) << "Failed to resolve '" << v.GetRefType()->GetName() << "'";
+        *success_ = false;
+        return;
+      }
+    }
+    const AidlConstantValue* resolved = v.Resolve();
+    if (!resolved) {
+      AIDL_ERROR(v.GetRefType()) << "Failed to resolve '" << v.GetRefType()->GetName() << "'";
+      *success_ = false;
+      return;
+    }
+
+    // resolve recursive references
+    Push(&v);
+    const_cast<AidlConstantValue*>(resolved)->Accept(*this);
+    Pop();
+  }
+
+ private:
+  struct StackElem {
+    const AidlDefinedType* scope;
+    const AidlConstantReference* ref;
+  };
+
+  void Push(const AidlConstantReference* ref) {
+    stack_.push_back({scope_, ref});
+    scope_ = ref->GetRefType()->GetDefinedType();
+  }
+
+  void Pop() {
+    scope_ = stack_.back().scope;
+    stack_.pop_back();
+  }
+
+  bool IsCircularReference(const AidlConstantReference* ref) {
+    auto it = std::find_if(stack_.begin(), stack_.end(),
+                           [&](const auto& elem) { return elem.ref == ref; });
+    if (it == stack_.end()) {
+      return false;
+    }
+    std::vector<std::string> path;
+    while (it != stack_.end()) {
+      path.push_back(it->ref->Literal());
+      ++it;
+    }
+    path.push_back(ref->Literal());
+    AIDL_ERROR(ref) << "Found a circular reference: " << android::base::Join(path, " -> ");
+    return true;
+  }
+
+  const AidlDefinedType* scope_;
+  const AidlTypenames& typenames_;
+  TypeResolver& resolver_;
+  bool* success_;
+  std::vector<StackElem> stack_ = {};
+};
+
+bool Parser::Resolve(TypeResolver& type_resolver) {
   bool success = true;
   for (AidlTypeSpecifier* typespec : unresolved_typespecs_) {
-    if (!typespec->Resolve(typenames_)) {
+    if (!type_resolver(document_, typespec)) {
       AIDL_ERROR(typespec) << "Failed to resolve '" << typespec->GetUnresolvedName() << "'";
       success = false;
       // don't stop to show more errors if any
     }
   }
 
-  struct ConstantReferenceResolver : public AidlConstantValue::Visitor {
-    const std::string name_;
-    const AidlTypenames& typenames_;
-    bool* success_;
-    ConstantReferenceResolver(const std::string& name, const AidlTypenames& typenames,
-                              bool* success)
-        : name_(name), typenames_(typenames), success_(success) {}
-    void Visit(AidlConstantValue&) override {}
-    void Visit(AidlUnaryConstExpression&) override {}
-    void Visit(AidlBinaryConstExpression&) override {}
-    void Visit(AidlConstantReference& v) override {
-      // when <type> is missing, we use
-      if (!v.GetRefType()) {
-        auto type = std::make_unique<AidlTypeSpecifier>(v.GetLocation(), name_, false, nullptr, "");
-        type->Resolve(typenames_);
-        v.SetRefType(std::move(type));
-      }
-      // check if the reference points to a valid field
-      if (!v.CheckValid()) {
-        *success_ = false;
-      }
-    }
-  };
   // resolve "field references" as well.
   for (const auto& type : document_->DefinedTypes()) {
-    ConstantReferenceResolver resolver{type->GetCanonicalName(), typenames_, &success};
+    ConstantReferenceResolver ref_resolver{type.get(), typenames_, type_resolver, &success};
     if (auto enum_type = type->AsEnumDeclaration(); enum_type) {
       for (const auto& enumerator : enum_type->GetEnumerators()) {
         if (auto value = enumerator->GetValue(); value) {
-          value->Accept(resolver);
+          value->Accept(ref_resolver);
         }
       }
     } else {
       for (const auto& constant : type->GetConstantDeclarations()) {
-        const_cast<AidlConstantValue&>(constant->GetValue()).Accept(resolver);
+        const_cast<AidlConstantValue&>(constant->GetValue()).Accept(ref_resolver);
       }
       for (const auto& field : type->GetFields()) {
         if (field->IsDefaultUserSpecified()) {
-          const_cast<AidlConstantValue*>(field->GetDefaultValue())->Accept(resolver);
+          const_cast<AidlConstantValue*>(field->GetDefaultValue())->Accept(ref_resolver);
         }
       }
     }