Be a little smarter about dealing with TypeDefs, resolve to the typedef'd

target at lookup time, so all code ever sees is anything _but_ TypeDefs.
Also verify that the optional Enum storage type is valid (i.e. an enum
or an integer type) and re-emit enum values for derived enum types.
diff --git a/AST.cpp b/AST.cpp
index d10a3ef..c26c99c 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -5,6 +5,7 @@
 #include "FQName.h"
 #include "HandleType.h"
 #include "Scope.h"
+#include "TypeDef.h"
 
 #include <android-base/logging.h>
 #include <stdlib.h>
@@ -183,6 +184,11 @@
             Type *type = mScopePath[i]->lookupType(name);
 
             if (type != NULL) {
+                // Resolve typeDefs to the target type.
+                while (type->isTypeDef()) {
+                    type = static_cast<TypeDef *>(type)->referencedType();
+                }
+
                 return type->ref();
             }
         }
@@ -228,6 +234,11 @@
         }
 
         if (dotPos == std::string::npos) {
+            // Resolve typeDefs to the target type.
+            while (type->isTypeDef()) {
+                type = static_cast<TypeDef *>(type)->referencedType();
+            }
+
             return type;
         }
 
diff --git a/EnumType.cpp b/EnumType.cpp
index 3cd8c8a..95cb6be 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -16,10 +16,22 @@
                 : new ScalarType(ScalarType::KIND_INT32)) {
 }
 
+const Type *EnumType::storageType() const {
+    return mStorageType;
+}
+
+const std::vector<EnumValue *> &EnumType::values() const {
+    return *mValues;
+}
+
 const ScalarType *EnumType::resolveToScalarType() const {
     return mStorageType->resolveToScalarType();
 }
 
+bool EnumType::isEnum() const {
+    return true;
+}
+
 std::string EnumType::getCppType(StorageMode, std::string *extra) const {
     extra->clear();
 
@@ -60,15 +72,32 @@
 
     out.indent();
 
-    for (const auto &entry : *mValues) {
-        out << entry->name();
+    std::vector<const EnumType *> chain;
+    const EnumType *type = this;
+    for (;;) {
+        chain.push_back(type);
 
-        const char *value = entry->value();
-        if (value != NULL) {
-            out << " = " << value;
+        const Type *superType = type->storageType();
+        if (superType == NULL || !superType->isEnum()) {
+            break;
         }
 
-        out << ",\n";
+        type = static_cast<const EnumType *>(superType);
+    }
+
+    for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+        const auto &type = *it;
+
+        for (const auto &entry : type->values()) {
+            out << entry->name();
+
+            const char *value = entry->value();
+            if (value != NULL) {
+                out << " = " << value;
+            }
+
+            out << ",\n";
+        }
     }
 
     out.unindent();
diff --git a/EnumType.h b/EnumType.h
index 2bb258c..939cd3b 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -14,8 +14,13 @@
     EnumType(std::vector<EnumValue *> *values,
              Type *storageType = NULL);
 
+    const Type *storageType() const;
+    const std::vector<EnumValue *> &values() const;
+
     const ScalarType *resolveToScalarType() const override;
 
+    bool isEnum() const override;
+
     std::string getCppType(StorageMode mode, std::string *extra) const override;
 
     void emitReaderWriter(
diff --git a/ScalarType.cpp b/ScalarType.cpp
index d612d9b..f308a72 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -12,6 +12,11 @@
     return this;
 }
 
+bool ScalarType::isValidEnumStorageType() const {
+    // Only integer types.
+    return mKind >= KIND_INT8 && mKind <= KIND_UINT64;
+}
+
 std::string ScalarType::getCppType(StorageMode, std::string *extra) const {
     static const char *const kName[] = {
         "char",
diff --git a/ScalarType.h b/ScalarType.h
index bc642f5..38b79d4 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -27,6 +27,8 @@
 
     const ScalarType *resolveToScalarType() const override;
 
+    bool isValidEnumStorageType() const;
+
     std::string getCppType(StorageMode mode, std::string *extra) const override;
 
     void emitReaderWriter(
diff --git a/Type.cpp b/Type.cpp
index 548e425..6d0e4e8 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -1,6 +1,7 @@
 #include "Type.h"
 
 #include "Formatter.h"
+#include "ScalarType.h"
 
 #include <android-base/logging.h>
 
@@ -17,10 +18,28 @@
     return false;
 }
 
+bool Type::isEnum() const {
+    return false;
+}
+
+bool Type::isTypeDef() const {
+    return false;
+}
+
 const ScalarType *Type::resolveToScalarType() const {
     return NULL;
 }
 
+bool Type::isValidEnumStorageType() const {
+    const ScalarType *scalarType = resolveToScalarType();
+
+    if (scalarType == NULL) {
+        return false;
+    }
+
+    return scalarType->isValidEnumStorageType();
+}
+
 std::string Type::getCppType(StorageMode, std::string *) const {
     CHECK(!"Should not be here");
     return std::string();
diff --git a/Type.h b/Type.h
index bf0b6c6..03c6615 100644
--- a/Type.h
+++ b/Type.h
@@ -19,8 +19,13 @@
 
     virtual bool isScope() const;
     virtual bool isInterface() const;
+    virtual bool isEnum() const;
+    virtual bool isTypeDef() const;
+
     virtual const ScalarType *resolveToScalarType() const;
 
+    bool isValidEnumStorageType() const;
+
     enum StorageMode {
         StorageMode_Stack,
         StorageMode_Argument,
diff --git a/TypeDef.cpp b/TypeDef.cpp
index 1d50e6e..1e3c5b7 100644
--- a/TypeDef.cpp
+++ b/TypeDef.cpp
@@ -2,6 +2,8 @@
 
 #include "Formatter.h"
 
+#include <android-base/logging.h>
+
 namespace android {
 
 TypeDef::TypeDef(Type *type)
@@ -10,60 +12,36 @@
 }
 
 const ScalarType *TypeDef::resolveToScalarType() const {
-    return mReferencedType->resolveToScalarType();
+    CHECK(!"Should not be here");
+    return NULL;
 }
 
-const Type *TypeDef::referencedType() const {
+Type *TypeDef::referencedType() const {
     return mReferencedType;
 }
 
 bool TypeDef::isInterface() const {
-    return mReferencedType->isInterface();
+    CHECK(!"Should not be here");
+    return false;
 }
 
-std::string TypeDef::getCppType(StorageMode mode, std::string *extra) const {
-    return mReferencedType->getCppType(mode, extra);
+bool TypeDef::isEnum() const {
+    CHECK(!"Should not be here");
+    return false;
 }
 
-void TypeDef::emitReaderWriter(
-        Formatter &out,
-        const std::string &name,
-        const std::string &parcelObj,
-        bool parcelObjIsPointer,
-        bool isReader,
-        ErrorMode mode) const {
-    mReferencedType->emitReaderWriter(
-            out, name, parcelObj, parcelObjIsPointer, isReader, mode);
-}
-
-void TypeDef::emitReaderWriterEmbedded(
-        Formatter &out,
-        const std::string &name,
-        bool nameIsPointer,
-        const std::string &parcelObj,
-        bool parcelObjIsPointer,
-        bool isReader,
-        ErrorMode mode,
-        const std::string &parentName,
-        const std::string &offsetText) const {
-    mReferencedType->emitReaderWriterEmbedded(
-            out,
-            name,
-            nameIsPointer,
-            parcelObj,
-            parcelObjIsPointer,
-            isReader,
-            mode,
-            parentName,
-            offsetText);
+bool TypeDef::isTypeDef() const {
+    return true;
 }
 
 bool TypeDef::needsEmbeddedReadWrite() const {
-    return mReferencedType->needsEmbeddedReadWrite();
+    CHECK(!"Should not be here");
+    return false;
 }
 
 bool TypeDef::resultNeedsDeref() const {
-    return mReferencedType->resultNeedsDeref();
+    CHECK(!"Should not be here");
+    return false;
 }
 
 }  // namespace android
diff --git a/TypeDef.h b/TypeDef.h
index 14e0727..f3030bf 100644
--- a/TypeDef.h
+++ b/TypeDef.h
@@ -11,30 +11,11 @@
 
     const ScalarType *resolveToScalarType() const override;
 
-    const Type *referencedType() const;
+    Type *referencedType() const;
 
     bool isInterface() const override;
-
-    std::string getCppType(StorageMode mode, std::string *extra) const override;
-
-    void emitReaderWriter(
-            Formatter &out,
-            const std::string &name,
-            const std::string &parcelObj,
-            bool parcelObjIsPointer,
-            bool isReader,
-            ErrorMode mode) const override;
-
-    void emitReaderWriterEmbedded(
-            Formatter &out,
-            const std::string &name,
-            bool nameIsPointer,
-            const std::string &parcelObj,
-            bool parcelObjIsPointer,
-            bool isReader,
-            ErrorMode mode,
-            const std::string &parentName,
-            const std::string &offsetText) const override;
+    bool isEnum() const override;
+    bool isTypeDef() const override;
 
     bool needsEmbeddedReadWrite() const override;
     bool resultNeedsDeref() const override;
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 81151a7..4f640ce 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -162,7 +162,6 @@
               YYERROR;
           }
 
-          // XXX What if $3 was a typedef _pointing_ to an interface...
           Interface *iface = new Interface(static_cast<Interface *>($3));
 
           // Register interface immediately so it can be referenced inside
@@ -331,7 +330,15 @@
 
 opt_storage_type
     : /* empty */ { $$ = NULL; }
-    | ':' fqname { $$ = $2; }
+    | ':' fqname
+      {
+          $$ = $2;
+
+          if ($$ != NULL && !$$->isValidEnumStorageType()) {
+              fprintf(stderr, "Invalid enum storage type specified.\n");
+              YYABORT;
+          }
+      }
     ;
 
 opt_comma