Merge "Fix code generation for nested structs."
diff --git a/AST.cpp b/AST.cpp
index 016204b..810633f 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -42,7 +42,7 @@
 
 AST::~AST() {
     delete mRootScope;
-    mRootScope = NULL;
+    mRootScope = nullptr;
 
     CHECK(mScanner == NULL);
 
@@ -95,6 +95,7 @@
     // LOG(INFO) << "importing " << fqName.string();
 
     if (fqName.name().empty()) {
+        // import a package
         std::vector<FQName> packageInterfaces;
 
         status_t err =
@@ -107,21 +108,67 @@
 
         for (const auto &subFQName : packageInterfaces) {
             AST *ast = mCoordinator->parse(subFQName, &mImportedASTs);
-            if (ast == NULL) {
+            if (ast == nullptr) {
                 return false;
             }
+            // all previous single type imports are ignored.
+            mImportedTypes.erase(ast);
         }
 
         return true;
     }
 
-    AST *importAST = mCoordinator->parse(fqName, &mImportedASTs);
+    AST *importAST;
 
-    if (importAST == NULL) {
-        return false;
+    // cases like android.hardware.foo@1.0::IFoo.Internal
+    //            android.hardware.foo@1.0::Abc.Internal
+
+    // assume it is an interface, and try to import it.
+    const FQName interfaceName = fqName.getTopLevelType();
+    importAST = mCoordinator->parse(interfaceName, &mImportedASTs);
+
+    if (importAST != nullptr) {
+        // cases like android.hardware.foo@1.0::IFoo.Internal
+        //        and android.hardware.foo@1.0::IFoo
+        if (fqName == interfaceName) {
+            // import a single file.
+            // all previous single type imports are ignored.
+            // cases like android.hardware.foo@1.0::IFoo
+            //        and android.hardware.foo@1.0::types
+            mImportedTypes.erase(importAST);
+            return true;
+        }
+
+        // import a single type from this file
+        // cases like android.hardware.foo@1.0::IFoo.Internal
+        FQName matchingName;
+        Type *match = importAST->findDefinedType(fqName, &matchingName);
+        if (match == nullptr) {
+            return false;
+        }
+        // will automatically create a set if it does not exist
+        mImportedTypes[importAST].insert(match);
+        return true;
     }
 
-    return true;
+    // probably a type in types.hal, like android.hardware.foo@1.0::Abc.Internal
+    FQName typesFQName = fqName.getTypesForPackage();
+    importAST = mCoordinator->parse(typesFQName, &mImportedASTs);
+
+    if (importAST != nullptr) {
+        // Attempt to find Abc.Internal in types.
+        FQName matchingName;
+        Type *match = importAST->findDefinedType(fqName, &matchingName);
+        if (match == nullptr) {
+            return false;
+        }
+        // will automatically create a set if not exist
+        mImportedTypes[importAST].insert(match);
+        return true;
+    }
+
+    // can't find an appropriate AST for fqName.
+    return false;
 }
 
 void AST::addImportedAST(AST *ast) {
@@ -212,7 +259,7 @@
 
     if (fqName.name().empty()) {
         // Given a package and version???
-        return NULL;
+        return nullptr;
     }
 
     if (fqName.package().empty() && fqName.version().empty()) {
@@ -221,7 +268,7 @@
         for (size_t i = mScopePath.size(); i-- > 0;) {
             Type *type = mScopePath[i]->lookupType(fqName);
 
-            if (type != NULL) {
+            if (type != nullptr) {
                 // Resolve typeDefs to the target type.
                 while (type->isTypeDef()) {
                     type = static_cast<TypeDef *>(type)->referencedType();
@@ -237,6 +284,10 @@
     FQName resolvedName;
 
     for (const auto &importedAST : mImportedASTs) {
+        if (mImportedTypes.find(importedAST) != mImportedTypes.end()) {
+            // ignore single type imports
+            continue;
+        }
         FQName matchingName;
         Type *match = importedAST->findDefinedType(fqName, &matchingName);
 
@@ -249,7 +300,34 @@
                 std::cerr << "  " << resolvedName.string() << "\n";
                 std::cerr << "  " << matchingName.string() << "\n";
 
-                return NULL;
+                return nullptr;
+            }
+
+            resolvedType = match;
+            returnedType = resolvedType;
+            resolvedName = matchingName;
+
+            // Keep going even after finding a match.
+        }
+    }
+
+    for (const auto &pair : mImportedTypes) {
+        AST *importedAST = pair.first;
+        std::set<Type *> importedTypes = pair.second;
+
+        FQName matchingName;
+        Type *match = importedAST->findDefinedType(fqName, &matchingName);
+        if (match != nullptr &&
+                importedTypes.find(match) != importedTypes.end()) {
+            if (resolvedType != nullptr) {
+                std::cerr << "ERROR: Unable to resolve type name '"
+                          << fqName.string()
+                          << "', multiple matches found:\n";
+
+                std::cerr << "  " << resolvedName.string() << "\n";
+                std::cerr << "  " << matchingName.string() << "\n";
+
+                return nullptr;
             }
 
             resolvedType = match;
diff --git a/AST.h b/AST.h
index 5195532..1f9b02f 100644
--- a/AST.h
+++ b/AST.h
@@ -123,6 +123,12 @@
     // A set of all ASTs we explicitly or implicitly (types.hal) import.
     std::set<AST *> mImportedASTs;
 
+    // If a single type (instead of the whole AST) is imported, the AST will be
+    // present as a key to this map, with the value being a list of types
+    // imported from this AST. If an AST appears in mImportedASTs but not in
+    // mImportedTypes, then the whole AST is imported.
+    std::map<AST *, std::set<Type *>> mImportedTypes;
+
     // Types keyed by full names defined in this AST.
     std::map<FQName, Type *> mDefinedTypesByFullName;
 
diff --git a/EnumType.cpp b/EnumType.cpp
index d5abf6d..5513596 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -329,6 +329,16 @@
         name = quotedString.substr(1, quotedString.size() - 2);
     }
 
+    std::string valuePrefix;
+
+    const AnnotationParam *prefixParam = annotation->getParam("value_prefix");
+    if (prefixParam != nullptr) {
+        CHECK_EQ(prefixParam->getValues()->size(), 1u);
+
+        std::string quotedString = prefixParam->getValues()->at(0);
+        valuePrefix = quotedString.substr(1, quotedString.size() - 2);
+    }
+
     const ScalarType *scalarType = mStorageType->resolveToScalarType();
     CHECK(scalarType != NULL);
 
@@ -349,7 +359,7 @@
         const auto &type = *it;
 
         for (const auto &entry : type->values()) {
-            out << entry->name();
+            out << valuePrefix << entry->name();
 
             std::string value = entry->cppValue(scalarType->getKind());
             CHECK(!value.empty()); // use autofilled values for c++.
diff --git a/FQName.cpp b/FQName.cpp
index 9bc271b..0169e0c 100644
--- a/FQName.cpp
+++ b/FQName.cpp
@@ -241,6 +241,10 @@
     return mName.substr(1);
 }
 
+FQName FQName::getTypesForPackage() const {
+    return FQName(package(), version(), "types");
+}
+
 const FQName FQName::getTopLevelType() const {
     auto idx = mName.find('.');
 
diff --git a/FQName.h b/FQName.h
index e2d0159..391ba3d 100644
--- a/FQName.h
+++ b/FQName.h
@@ -99,11 +99,16 @@
     // -> Bar
     std::string getInterfaceBaseName() const;
 
+    // Replace whatever after :: with "types"
+    // android.hardware.foo@1.0::Abc.Type:VALUE
+    // -> android.hardware.foo@1.0::types
+    FQName getTypesForPackage() const;
+
     // the following comments all assume that the FQName
-    // is ::android::hardware::Foo::V1_0::IBar::Baz
+    // is android.hardware.foo@1.0::IBar.Baz.Bam
 
     // returns highest type in the hidl namespace, i.e.
-    // ::android::hardware::Foo::V1_0::IBar
+    // android.hardware.foo@1.0::IBar
     const FQName getTopLevelType() const;
 
     // returns an unambiguous fully qualified name which can be