Implement constant expression tags.

There is only one right now (#len). This gives the unique number of
elements in an enum.

An example usage is this:

enum Values : uint32_t { A, B, C };
struct Foo {
    float[Values#len] values;
};

This declares a float array whose indices are A, B, C (since A is
implicitly 0).

This has been done by combining the constant expression local
identifier lookup phase with lookups for this additional type. Notice
that just like with local identifiers, these type lookups cannot cause
cycles.

Change-Id: I95dd59eb28823d12b17d7d274e8289255ef1a09c
Fixes: 117951873
Test: hidl_test
Test: hidl_error_test
diff --git a/ConstantExpression.cpp b/ConstantExpression.cpp
index a025dd2..002bf56 100644
--- a/ConstantExpression.cpp
+++ b/ConstantExpression.cpp
@@ -355,6 +355,38 @@
     mIsEvaluated = true;
 }
 
+status_t AttributeConstantExpression::validate() const {
+    if (mTag == "len") {
+        if (!mReference->isEnum()) {
+            std::cerr << "ERROR: " << mExpr << " refers to " << mReference->typeName()
+                      << " but should refer to an enum." << std::endl;
+            return UNKNOWN_ERROR;
+        }
+    } else {
+        std::cerr << "ERROR: " << mExpr << " is not a supported tag" << std::endl;
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+void AttributeConstantExpression::evaluate() {
+    if (isEvaluated()) return;
+
+    CHECK(mTag == "len");
+    CHECK(mReference->isEnum());
+
+    EnumType* enumType = static_cast<EnumType*>(mReference.get());
+    mValue = enumType->numValueNames();
+
+    if (mValue <= INT32_MAX)
+        mValueKind = SK(INT32);
+    else
+        mValueKind = SK(INT64);
+
+    mIsEvaluated = true;
+}
+
 std::unique_ptr<ConstantExpression> ConstantExpression::addOne(ScalarType::Kind baseKind) {
     auto ret = std::make_unique<BinaryConstantExpression>(
         this, "+", ConstantExpression::One(baseKind).release());
@@ -479,6 +511,10 @@
     return false;
 }
 
+status_t ConstantExpression::validate() const {
+    return OK;
+}
+
 std::vector<ConstantExpression*> ConstantExpression::getConstantExpressions() {
     const auto& constRet = static_cast<const ConstantExpression*>(this)->getConstantExpressions();
     std::vector<ConstantExpression*> ret(constRet.size());
@@ -499,6 +535,18 @@
     return {};
 }
 
+std::vector<Reference<Type>*> ConstantExpression::getTypeReferences() {
+    const auto& constRet = static_cast<const ConstantExpression*>(this)->getTypeReferences();
+    std::vector<Reference<Type>*> ret(constRet.size());
+    std::transform(constRet.begin(), constRet.end(), ret.begin(),
+                   [](const auto* ce) { return const_cast<Reference<Type>*>(ce); });
+    return ret;
+}
+
+std::vector<const Reference<Type>*> ConstantExpression::getTypeReferences() const {
+    return {};
+}
+
 status_t ConstantExpression::recursivePass(const std::function<status_t(ConstantExpression*)>& func,
                                            std::unordered_set<const ConstantExpression*>* visited,
                                            bool processBeforeDependencies) {
@@ -678,6 +726,22 @@
     return {&mReference};
 }
 
+AttributeConstantExpression::AttributeConstantExpression(const Reference<Type>& value,
+                                                         const std::string& fqname,
+                                                         const std::string& tag)
+    : mReference(value), mTag(tag) {
+    mExpr = fqname + "#" + tag;
+}
+
+std::vector<const ConstantExpression*> AttributeConstantExpression::getConstantExpressions() const {
+    // Returns reference instead
+    return {};
+}
+
+std::vector<const Reference<Type>*> AttributeConstantExpression::getTypeReferences() const {
+    return {&mReference};
+}
+
 /*
 
 Evaluating expressions in HIDL language