Merge "update makefile rule to package test modules as part of VTS"
diff --git a/AST.cpp b/AST.cpp
index 5939e85..66e54c4 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -18,7 +18,7 @@
     : mCoordinator(coordinator),
       mPath(path),
       mScanner(NULL),
-      mRootScope(new Scope) {
+      mRootScope(new Scope("" /* localName */)) {
     enterScope(mRootScope);
 }
 
@@ -128,10 +128,9 @@
             localName, new TypeDef(type), errorMsg, true /* isTypeDef */);
 }
 
-bool AST::addScopedType(
-        const char *localName, NamedType *type, std::string *errorMsg) {
+bool AST::addScopedType(NamedType *type, std::string *errorMsg) {
     return addScopedTypeInternal(
-            localName, type, errorMsg, false /* isTypeDef */);
+            type->localName().c_str(), type, errorMsg, false /* isTypeDef */);
 }
 
 bool AST::addScopedTypeInternal(
@@ -146,14 +145,6 @@
         }
     }
 
-    std::string anonName;
-
-    if (localName == nullptr) {
-        // Anonymous type declaration.
-        anonName = scope()->pickUniqueAnonymousName();
-        localName = anonName.c_str();
-    }
-
     // LOG(INFO) << "adding scoped type '" << localName << "'";
 
     bool success = scope()->addType(localName, type,  errorMsg);
@@ -174,7 +165,6 @@
         CHECK(type->isNamedType());
 
         NamedType *namedType = static_cast<NamedType *>(type);
-        namedType->setLocalName(localName);
         namedType->setFullName(fqName);
     }
 
diff --git a/AST.h b/AST.h
index e2b68cf..ce7f31f 100644
--- a/AST.h
+++ b/AST.h
@@ -41,8 +41,7 @@
     bool addTypeDef(const char *localName, Type *type, std::string *errorMsg);
 
     // Returns true iff successful.
-    bool addScopedType(
-            const char *localName, NamedType *type, std::string *errorMsg);
+    bool addScopedType(NamedType *type, std::string *errorMsg);
 
     void *scanner();
     void setScanner(void *scanner);
@@ -141,9 +140,13 @@
 
     status_t emitTypeDeclarations(Formatter &out) const;
     status_t emitJavaTypeDeclarations(Formatter &out) const;
+    status_t emitVtsTypeDeclarations(Formatter &out) const;
 
-    status_t emitVtsTypeDeclarations(
-            Formatter &out, const std::vector<Type *> &types) const;
+    // Helper function that generates vts type declaration from the current
+    // AST and the transitive closure of imported ASTs.
+    status_t emitVtsTypeDeclarationsHelper(
+                Formatter &out,
+                std::set<AST*> *allImportSet) const;
 
     DISALLOW_COPY_AND_ASSIGN(AST);
 };
diff --git a/ArrayType.cpp b/ArrayType.cpp
index 1c4217c..43e0fd0 100644
--- a/ArrayType.cpp
+++ b/ArrayType.cpp
@@ -163,7 +163,7 @@
 status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
     out << "type: TYPE_ARRAY\n" << "vector_value: {\n";
     out.indent();
-    out << "size: " << mDimension;
+    out << "size: " << mDimension << "\n";
     status_t err = mElementType->emitVtsTypeDeclarations(out);
     if (err != OK) {
         return err;
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 015b576..768c820 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -6,8 +6,9 @@
 
 namespace android {
 
-CompoundType::CompoundType(Style style)
-    : mStyle(style),
+CompoundType::CompoundType(Style style, const char *localName)
+    : Scope(localName),
+      mStyle(style),
       mFields(NULL) {
 }
 
@@ -302,34 +303,73 @@
     switch (mStyle) {
         case STYLE_STRUCT:
         {
-            out << "type: TYPE_STRUCT\n" << "struct value: {\n";
+            out << "type: TYPE_STRUCT\n";
             break;
         }
         case STYLE_UNION:
         {
-            out << "type: TYPE_UNION\n" << "union value: {\n";
+            out << "type: TYPE_UNION\n";
             break;
         }
         default:
             break;
     }
-    out.indent();
-    // Emit declaration for all subtypes.
-    Scope::emitVtsTypeDeclarations(out);
-    // Emit declaration for all fields.
-    for (const auto &field : *mFields) {
-        status_t status = field->type().emitVtsTypeDeclarations(out);
+
+    // Emit declaration for each subtype.
+    for (const auto &type : getSubTypes()) {
+        switch (mStyle) {
+            case STYLE_STRUCT:
+            {
+                out << "struct_value: {\n";
+                break;
+            }
+            case STYLE_UNION:
+            {
+                out << "union_value: {\n";
+                break;
+            }
+            default:
+                break;
+        }
+        out.indent();
+        status_t status(type->emitVtsTypeDeclarations(out));
         if (status != OK) {
             return status;
         }
+        out.unindent();
+        out << "}\n";
     }
-    out.unindent();
-    out << "}\n";
+
+    // Emit declaration for each field.
+    for (const auto &field : *mFields) {
+        switch (mStyle) {
+            case STYLE_STRUCT:
+            {
+                out << "struct_value: {\n";
+                break;
+            }
+            case STYLE_UNION:
+            {
+                out << "union_value: {\n";
+                break;
+            }
+            default:
+                break;
+        }
+        out.indent();
+        out << "name: \"" << field->name() << "\"\n";
+        status_t status = field->type().emitVtsAttributeType(out);
+        if (status != OK) {
+            return status;
+        }
+        out.unindent();
+        out << "}\n";
+    }
 
     return OK;
 }
 
-status_t CompoundType::emitVtsArgumentType(Formatter &out) const {
+status_t CompoundType::emitVtsAttributeType(Formatter &out) const {
     switch (mStyle) {
         case STYLE_STRUCT:
         {
diff --git a/CompoundType.h b/CompoundType.h
index 3628b52..6d5724f 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -16,7 +16,7 @@
         STYLE_UNION,
     };
 
-    CompoundType(Style style);
+    CompoundType(Style style, const char *localName);
 
     bool setFields(std::vector<CompoundField *> *fields, std::string *errorMsg);
 
@@ -50,7 +50,7 @@
     bool resultNeedsDeref() const override;
 
     status_t emitVtsTypeDeclarations(Formatter &out) const override;
-    status_t emitVtsArgumentType(Formatter &out) const override;
+    status_t emitVtsAttributeType(Formatter &out) const override;
 
     bool isJavaCompatible() const override;
 
diff --git a/EnumType.cpp b/EnumType.cpp
index 3a9a3c2..3f9b3dd 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -8,8 +8,11 @@
 namespace android {
 
 EnumType::EnumType(
-        std::vector<EnumValue *> *values, Type *storageType)
-    : mValues(values),
+        const char *localName,
+        std::vector<EnumValue *> *values,
+        Type *storageType)
+    : NamedType(localName),
+      mValues(values),
       mStorageType(
               storageType != NULL
                 ? storageType
@@ -81,17 +84,7 @@
     out.indent();
 
     std::vector<const EnumType *> chain;
-    const EnumType *type = this;
-    for (;;) {
-        chain.push_back(type);
-
-        const Type *superType = type->storageType();
-        if (superType == NULL || !superType->isEnum()) {
-            break;
-        }
-
-        type = static_cast<const EnumType *>(superType);
-    }
+    getTypeChain(&chain);
 
     for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
         const auto &type = *it;
@@ -157,17 +150,7 @@
     const std::string typeName = scalarType->getJavaType();
 
     std::vector<const EnumType *> chain;
-    const EnumType *type = this;
-    for (;;) {
-        chain.push_back(type);
-
-        const Type *superType = type->storageType();
-        if (superType == NULL || !superType->isEnum()) {
-            break;
-        }
-
-        type = static_cast<const EnumType *>(superType);
-    }
+    getTypeChain(&chain);
 
     for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
         const auto &type = *it;
@@ -203,30 +186,52 @@
 }
 
 status_t EnumType::emitVtsTypeDeclarations(Formatter &out) const {
-    out << "name: \""
-        << localName()
-        << "\"\n"
+    out << "name: \"" << localName() << "\"\n"
         << "type: TYPE_ENUM\n"
         << "enum_value: {\n";
     out.indent();
-    for (const auto &entry : values()) {
-        out << "enumerator: \""
-            << entry->name()
-            << "\"\n"
-            << "value: "
-            << entry->value()
-            << "\n";
+
+    std::vector<const EnumType *> chain;
+    getTypeChain(&chain);
+
+    for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+        const auto &type = *it;
+
+        for (const auto &entry : type->values()) {
+            out << "enumerator: \"" << entry->name() << "\"\n";
+
+            const char *value = entry->value();
+            if (value != NULL) {
+                out << "value: " << value << "\n";
+            }
+        }
     }
+
     out.unindent();
     out << "}\n";
     return OK;
 }
 
-status_t EnumType::emitVtsArgumentType(Formatter &out) const {
+status_t EnumType::emitVtsAttributeType(Formatter &out) const {
     out << "type: TYPE_ENUM\n" << "predefined_type:\"" << localName() << "\"\n";
     return OK;
 }
 
+void EnumType::getTypeChain(std::vector<const EnumType *> *out) const {
+    out->clear();
+    const EnumType *type = this;
+    for (;;) {
+        out->push_back(type);
+
+        const Type *superType = type->storageType();
+        if (superType == NULL || !superType->isEnum()) {
+            break;
+        }
+
+        type = static_cast<const EnumType *>(superType);
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 EnumValue::EnumValue(const char *name, const char *value)
diff --git a/EnumType.h b/EnumType.h
index 7aa55e5..0d38636 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -11,7 +11,8 @@
 struct EnumValue;
 
 struct EnumType : public NamedType {
-    EnumType(std::vector<EnumValue *> *values,
+    EnumType(const char *localName,
+             std::vector<EnumValue *> *values,
              Type *storageType = NULL);
 
     const Type *storageType() const;
@@ -38,9 +39,10 @@
     status_t emitJavaTypeDeclarations(Formatter &out) const override;
 
     status_t emitVtsTypeDeclarations(Formatter &out) const override;
-    status_t emitVtsArgumentType(Formatter &out) const override;
+    status_t emitVtsAttributeType(Formatter &out) const override;
 
 private:
+    void getTypeChain(std::vector<const EnumType *> *out) const;
     std::vector<EnumValue *> *mValues;
     Type *mStorageType;
 
diff --git a/GenericBinder.cpp b/GenericBinder.cpp
index 6baf538..96f5dc1 100644
--- a/GenericBinder.cpp
+++ b/GenericBinder.cpp
@@ -76,7 +76,7 @@
     }
 }
 
-status_t GenericBinder::emitVtsArgumentType(Formatter &) const {
+status_t GenericBinder::emitVtsAttributeType(Formatter &) const {
     return UNKNOWN_ERROR;
 }
 
diff --git a/GenericBinder.h b/GenericBinder.h
index c5616f5..7957bde 100644
--- a/GenericBinder.h
+++ b/GenericBinder.h
@@ -28,7 +28,7 @@
             const std::string &argName,
             bool isReader) const override;
 
-    status_t emitVtsArgumentType(Formatter &out) const override;
+    status_t emitVtsAttributeType(Formatter &out) const override;
 };
 
 }  // namespace android
diff --git a/Interface.cpp b/Interface.cpp
index 52c1963..6af96d3 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -4,10 +4,14 @@
 #include "Formatter.h"
 #include "Method.h"
 
+#include <iostream>
+
 namespace android {
 
-Interface::Interface(Interface *super, AnnotationVector *annotations)
-    : mSuperType(super),
+Interface::Interface(
+        const char *localName, Interface *super, AnnotationVector *annotations)
+    : Scope(localName),
+      mSuperType(super),
       mAnnotationsByName(annotations),
       mIsJavaCompatibleInProgress(false) {
 }
@@ -123,7 +127,80 @@
     }
 }
 
-status_t Interface::emitVtsArgumentType(Formatter &out) const {
+status_t Interface::emitVtsAttributeDeclaration(Formatter &out) const {
+    for (const auto &type : getSubTypes()) {
+        out << "attribute: {\n";
+        out.indent();
+        status_t status = type->emitVtsTypeDeclarations(out);
+        if (status != OK) {
+            return status;
+        }
+        out.unindent();
+        out << "}\n\n";
+    }
+    return OK;
+}
+
+status_t Interface::emitVtsMethodDeclaration(Formatter &out) const {
+    for (const auto &method : mMethods) {
+        out << "api: {\n";
+        out.indent();
+        out << "name: \"" << method->name() << "\"\n";
+        // Generate declaration for each return value.
+        for (const auto &result : method->results()) {
+            out << "return_type_hidl: {\n";
+            out.indent();
+            status_t status = result->type().emitVtsAttributeType(out);
+            if (status != OK) {
+                return status;
+            }
+            out.unindent();
+            out << "}\n";
+        }
+        // Generate declaration for each input argument
+        for (const auto &arg : method->args()) {
+            out << "arg: {\n";
+            out.indent();
+            status_t status = arg->type().emitVtsAttributeType(out);
+            if (status != OK) {
+                return status;
+            }
+            out.unindent();
+            out << "}\n";
+        }
+        // Generate declaration for each annotation.
+        const AnnotationVector & annotations = method->annotations();
+        for (size_t i = 0; i < annotations.size(); i++) {
+            out << "callflow: {\n";
+            out.indent();
+            std::string name = annotations.keyAt(i);
+            if (name == "entry") {
+                out << "entry: true\n";
+            } else if (name == "exit") {
+                out << "exit: true\n";
+            } else if (name == "callflow") {
+                Annotation* annotation = annotations.valueAt(i);
+                std::vector<std::string> * values = annotation->params()
+                        .valueFor("next");
+                for (auto value : *values) {
+                    out << "next: " << value << "\n";
+                }
+            } else {
+                std::cerr << "Invalid annotation '"
+                          << name << "' for method: " << method->name()
+                          << ". Should be one of: entry, exit, callflow. \n";
+                return UNKNOWN_ERROR;
+            }
+            out.unindent();
+            out << "}\n";
+        }
+        out.unindent();
+        out << "}\n\n";
+    }
+    return OK;
+}
+
+status_t Interface::emitVtsAttributeType(Formatter &out) const {
     out << "type: TYPE_HIDL_CALLBACK\n"
         << "predefined_type: \""
         << localName()
diff --git a/Interface.h b/Interface.h
index d825122..da76519 100644
--- a/Interface.h
+++ b/Interface.h
@@ -15,6 +15,7 @@
 
 struct Interface : public Scope {
     Interface(
+            const char *localName,
             Interface *super,
             AnnotationVector *annotations);
 
@@ -47,7 +48,10 @@
             const std::string &argName,
             bool isReader) const override;
 
-    status_t emitVtsArgumentType(Formatter &out) const override;
+    status_t emitVtsAttributeType(Formatter &out) const override;
+
+    status_t emitVtsAttributeDeclaration(Formatter &out) const;
+    status_t emitVtsMethodDeclaration(Formatter &out) const;
 
     bool isJavaCompatible() const override;
 
diff --git a/NamedType.cpp b/NamedType.cpp
index ddefff7..d3b48f2 100644
--- a/NamedType.cpp
+++ b/NamedType.cpp
@@ -2,16 +2,14 @@
 
 namespace android {
 
-NamedType::NamedType() {}
+NamedType::NamedType(const char *localName)
+    : mLocalName(localName) {
+}
 
 bool NamedType::isNamedType() const {
     return true;
 }
 
-void NamedType::setLocalName(const std::string &localName) {
-    mLocalName = localName;
-}
-
 void NamedType::setFullName(const FQName &fullName) {
     mFullName = fullName;
 }
diff --git a/NamedType.h b/NamedType.h
index 52a7434..5f79bf6 100644
--- a/NamedType.h
+++ b/NamedType.h
@@ -11,11 +11,10 @@
 namespace android {
 
 struct NamedType : public Type {
-    NamedType();
+    NamedType(const char *localName);
 
     bool isNamedType() const override;
 
-    void setLocalName(const std::string &localName);
     void setFullName(const FQName &fullName);
 
     const FQName &fqName() const;
diff --git a/ScalarType.cpp b/ScalarType.cpp
index 479a6b5..036ba46 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -143,7 +143,6 @@
     handleError(out, mode);
 }
 
-
 status_t ScalarType::emitVtsTypeDeclarations(Formatter &out) const {
     std::string extra;
     out << "type: TYPE_SCALAR\n"
diff --git a/Scope.cpp b/Scope.cpp
index 28570e0..c72c72a 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -7,7 +7,9 @@
 
 namespace android {
 
-Scope::Scope() {}
+Scope::Scope(const char *localName)
+    : NamedType(localName) {
+}
 
 bool Scope::addType(const char *localName, Type *type, std::string *errorMsg) {
     if (mTypeIndexByName.indexOfKey(localName) >= 0) {
@@ -112,7 +114,6 @@
     return OK;
 }
 
-
 const std::vector<Type *> &Scope::getSubTypes() const {
     return mTypes;
 }
diff --git a/Scope.h b/Scope.h
index 4a77a7c..5a90abe 100644
--- a/Scope.h
+++ b/Scope.h
@@ -13,7 +13,7 @@
 struct Interface;
 
 struct Scope : public NamedType {
-    Scope();
+    Scope(const char *localName);
 
     bool addType(const char *localName, Type *type, std::string *errorMsg);
 
diff --git a/Type.cpp b/Type.cpp
index da45677..907a0c2 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -267,7 +267,7 @@
     return OK;
 }
 
-status_t Type::emitVtsArgumentType(Formatter &out) const {
+status_t Type::emitVtsAttributeType(Formatter &out) const {
     return emitVtsTypeDeclarations(out);
 }
 
diff --git a/Type.h b/Type.h
index dbb190b..6ee76ca 100644
--- a/Type.h
+++ b/Type.h
@@ -89,8 +89,9 @@
     // Generates type declaration for vts proto file.
     // TODO (b/30844146): make it a pure virtual method.
     virtual status_t emitVtsTypeDeclarations(Formatter &out) const;
-    // Generates type declaration as method argument for vts proto file.
-    virtual status_t emitVtsArgumentType(Formatter &out) const;
+    // Generates type declaration as attribute of method (return value or method
+    // argument) or attribute of compound type for vts proto file.
+    virtual status_t emitVtsAttributeType(Formatter &out) const;
 
     // Returns true iff this type is supported through the Java backend.
     virtual bool isJavaCompatible() const;
diff --git a/VectorType.cpp b/VectorType.cpp
index 44c7e59..e180f22 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -179,6 +179,18 @@
     return OK;
 }
 
+status_t VectorType::emitVtsAttributeType(Formatter &out) const {
+    out << "type: TYPE_VECTOR\n" << "vector_value: {\n";
+    out.indent();
+    status_t status = mElementType->emitVtsAttributeType(out);
+    if (status != OK) {
+        return status;
+    }
+    out.unindent();
+    out << "}\n";
+    return OK;
+}
+
 bool VectorType::isJavaCompatible() const {
     return mElementType->isJavaCompatible();
 }
diff --git a/VectorType.h b/VectorType.h
index c4dbd63..9f76314 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -37,6 +37,7 @@
     bool resultNeedsDeref() const override;
 
     status_t emitVtsTypeDeclarations(Formatter &out) const override;
+    status_t emitVtsAttributeType(Formatter &out) const override;
 
     bool isJavaCompatible() const override;
 
diff --git a/generateVts.cpp b/generateVts.cpp
index d1847ba..1a56c1b 100644
--- a/generateVts.cpp
+++ b/generateVts.cpp
@@ -19,10 +19,33 @@
     return out.substr(1, out.size() - 2);
 }
 
-status_t AST::emitVtsTypeDeclarations(
+status_t AST::emitVtsTypeDeclarations(Formatter &out) const {
+    std::set<AST *> allImportedASTs;
+    return emitVtsTypeDeclarationsHelper(out, &allImportedASTs);
+}
+
+status_t AST::emitVtsTypeDeclarationsHelper(
         Formatter &out,
-        const std::vector<Type *> &types) const {
-    for (const auto& type : types) {
+        std::set<AST *> *allImportSet) const {
+    // First, generate vts type declaration for all imported AST.
+    for (const auto &ast : mImportedASTs) {
+        // Already processed, skip.
+        if (allImportSet->find(ast) != allImportSet->end()) {
+            continue;
+        }
+        allImportSet->insert(ast);
+        std::string ifaceName;
+        // We only care about types.hal.
+        if (!ast->isInterface(&ifaceName)) {
+            status_t status = ast->emitVtsTypeDeclarationsHelper(
+                    out, allImportSet);
+            if (status != OK) {
+                return status;
+            }
+        }
+    }
+    // Next, generate vts type declaration for the current AST.
+    for (const auto &type : mRootScope->getSubTypes()) {
         out << "attribute: {\n";
         out.indent();
         status_t status = type->emitVtsTypeDeclarations(out);
@@ -98,44 +121,34 @@
         out << "interface: {\n";
         out.indent();
 
-        status_t status = emitVtsTypeDeclarations(out, iface->getSubTypes());
-        if (status != OK) {
-            return status;
+        std::vector<const Interface *> chain;
+        while (iface != NULL) {
+            chain.push_back(iface);
+            iface = iface->superType();
         }
 
-        for (const auto &method : iface->methods()) {
-            out << "api: {\n";
-            out.indent();
-            out << "name: \"" << method->name() << "\"\n";
-            for (const auto &result : method->results()) {
-                out << "return_type_hidl: {\n";
-                out.indent();
-                status_t status = result->type().emitVtsArgumentType(out);
-                if (status != OK) {
-                    return status;
-                }
-                out.unindent();
-                out << "}\n";
+        // Generate all the attribute declarations first.
+        for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+            const Interface *superInterface = *it;
+            status_t status = superInterface->emitVtsAttributeDeclaration(out);
+            if (status != OK) {
+                return status;
             }
-            for (const auto &arg : method->args()) {
-                out << "arg: {\n";
-                out.indent();
-                status_t status = arg->type().emitVtsArgumentType(out);
-                if (status != OK) {
-                    return status;
-                }
-                out.unindent();
-                out << "}\n";
+        }
+
+        // Generate all the method declarations.
+        for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+            const Interface *superInterface = *it;
+            status_t status = superInterface->emitVtsMethodDeclaration(out);
+            if (status != OK) {
+                return status;
             }
-            out.unindent();
-            out << "}\n\n";
         }
 
         out.unindent();
         out << "}\n";
     } else {
-        status_t status = emitVtsTypeDeclarations(out,
-                                                  mRootScope->getSubTypes());
+        status_t status = emitVtsTypeDeclarations(out);
         if (status != OK) {
             return status;
         }
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 5867f4a..31568b8 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -282,12 +282,12 @@
               YYERROR;
           }
 
-          Interface *iface = new Interface(static_cast<Interface *>($4), $1);
+          Interface *iface = new Interface($3, static_cast<Interface *>($4), $1);
 
           // Register interface immediately so it can be referenced inside
           // definition.
           std::string errorMsg;
-          if (!ast->addScopedType($3, iface, &errorMsg)) {
+          if (!ast->addScopedType(iface, &errorMsg)) {
               std::cerr << "ERROR: " << errorMsg << " at " << @3 << "\n";
               YYERROR;
           }
@@ -411,7 +411,7 @@
 named_struct_or_union_declaration
     : struct_or_union_keyword IDENTIFIER
       {
-          CompoundType *container = new CompoundType($1);
+          CompoundType *container = new CompoundType($1, $2);
           ast->enterScope(container);
       }
       struct_or_union_body
@@ -426,7 +426,7 @@
 
           ast->leaveScope();
 
-          if (!ast->addScopedType($2, container, &errorMsg)) {
+          if (!ast->addScopedType(container, &errorMsg)) {
               std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
@@ -436,7 +436,14 @@
 struct_or_union_declaration
     : struct_or_union_keyword optIdentifier
       {
-          CompoundType *container = new CompoundType($1);
+          const char *localName = $2;
+          std::string anonName;
+          if (localName == nullptr) {
+              anonName = ast->scope()->pickUniqueAnonymousName();
+              localName = anonName.c_str();
+          }
+
+          CompoundType *container = new CompoundType($1, localName);
           ast->enterScope(container);
       }
       struct_or_union_body
@@ -451,7 +458,7 @@
 
           ast->leaveScope();
 
-          if (!ast->addScopedType($2, container, &errorMsg)) {
+          if (!ast->addScopedType(container, &errorMsg)) {
               std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
@@ -505,10 +512,10 @@
 named_enum_declaration
     : ENUM IDENTIFIER opt_storage_type '{' enum_values opt_comma '}'
       {
-          EnumType *enumType = new EnumType($5, $3);
+          EnumType *enumType = new EnumType($2, $5, $3);
 
           std::string errorMsg;
-          if (!ast->addScopedType($2, enumType, &errorMsg)) {
+          if (!ast->addScopedType(enumType, &errorMsg)) {
               std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
@@ -518,10 +525,12 @@
 enum_declaration
     : ENUM '{' enum_values opt_comma '}'
       {
-          EnumType *enumType = new EnumType($3);
+          std::string anonName = ast->scope()->pickUniqueAnonymousName();
+
+          EnumType *enumType = new EnumType(anonName.c_str(), $3);
 
           std::string errorMsg;
-          if (!ast->addScopedType(NULL /* localName */, enumType, &errorMsg)) {
+          if (!ast->addScopedType(enumType, &errorMsg)) {
               // This should never fail.
               std::cerr << "ERROR: " << errorMsg << "\n";
               YYERROR;
@@ -531,10 +540,10 @@
       }
     | ENUM IDENTIFIER opt_storage_type '{' enum_values opt_comma '}'
       {
-          EnumType *enumType = new EnumType($5, $3);
+          EnumType *enumType = new EnumType($2, $5, $3);
 
           std::string errorMsg;
-          if (!ast->addScopedType($2, enumType, &errorMsg)) {
+          if (!ast->addScopedType(enumType, &errorMsg)) {
               std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
diff --git a/test/data/android/hardware/nfc/1.0/types.vts b/test/data/android/hardware/nfc/1.0/types.vts
index 9645c79..89a3fba 100644
--- a/test/data/android/hardware/nfc/1.0/types.vts
+++ b/test/data/android/hardware/nfc/1.0/types.vts
@@ -46,7 +46,8 @@
 attribute: {
   name: "nfc_data_t"
   type: TYPE_STRUCT
-  struct value: {
+  struct_value: {
+    name: "data"
     type: TYPE_VECTOR
     vector_value: {
       type: TYPE_SCALAR