Allow struct, union and enum type declarations to be annotated.

Change-Id: Idce594b47c324d8420638e2e8853da3c99150672
Bug: 31800672
Test: hidl_test, hidl_test_java
diff --git a/AST.cpp b/AST.cpp
index c2bfc68..555f084 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -82,6 +82,10 @@
     return mRootScope->containsSingleInterface(ifaceName);
 }
 
+bool AST::containsInterfaces() const {
+    return mRootScope->containsInterfaces();
+}
+
 bool AST::addImport(const char *import) {
     FQName fqName(import);
     CHECK(fqName.isValid());
diff --git a/AST.h b/AST.h
index 2d64972..4f1d373 100644
--- a/AST.h
+++ b/AST.h
@@ -48,6 +48,7 @@
     // package and version really.
     FQName package() const;
     bool isInterface(std::string *ifaceName) const;
+    bool containsInterfaces() const;
 
     void enterScope(Scope *container);
     void leaveScope();
diff --git a/Coordinator.cpp b/Coordinator.cpp
index a7f0795..2e17b61 100644
--- a/Coordinator.cpp
+++ b/Coordinator.cpp
@@ -127,6 +127,13 @@
                     fqName.name().c_str());
 
             err = UNKNOWN_ERROR;
+        } else if (ast->containsInterfaces()) {
+            fprintf(stderr,
+                    "ERROR: types.hal file at '%s' declares at least one "
+                    "interface type.\n",
+                    path.c_str());
+
+            err = UNKNOWN_ERROR;
         }
     }
 
diff --git a/Interface.cpp b/Interface.cpp
index a5d3c9b..ba5ea8c 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -24,12 +24,9 @@
 
 namespace android {
 
-Interface::Interface(
-        const char *localName, Interface *super,
-        std::vector<Annotation *> *annotations)
+Interface::Interface(const char *localName, Interface *super)
     : Scope(localName),
       mSuperType(super),
-      mAnnotations(annotations),
       mIsJavaCompatibleInProgress(false) {
 }
 
@@ -53,10 +50,6 @@
     return mMethods;
 }
 
-const std::vector<Annotation *> &Interface::annotations() const {
-    return *mAnnotations;
-}
-
 std::string Interface::getBaseName() const {
     return fqName().getInterfaceBaseName();
 }
diff --git a/Interface.h b/Interface.h
index 0f12688..1c793e7 100644
--- a/Interface.h
+++ b/Interface.h
@@ -20,18 +20,12 @@
 
 #include "Scope.h"
 
-#include <vector>
-
 namespace android {
 
-struct Annotation;
 struct Method;
 
 struct Interface : public Scope {
-    Interface(
-            const char *localName,
-            Interface *super,
-            std::vector<Annotation *> *annotations);
+    Interface(const char *localName, Interface *super);
 
     void addMethod(Method *method);
 
@@ -42,8 +36,6 @@
 
     const std::vector<Method *> &methods() const;
 
-    const std::vector<Annotation *> &annotations() const;
-
     std::string getBaseName() const;
 
     std::string getCppType(
@@ -80,7 +72,6 @@
 private:
     Interface *mSuperType;
     std::vector<Method *> mMethods;
-    std::vector<Annotation *> *mAnnotations;
     mutable bool mIsJavaCompatibleInProgress;
 
     DISALLOW_COPY_AND_ASSIGN(Interface);
diff --git a/Scope.cpp b/Scope.cpp
index c4cc587..be60c95 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -85,6 +85,16 @@
     return false;
 }
 
+bool Scope::containsInterfaces() const {
+    for (const NamedType *type : mTypes) {
+        if (type->isInterface()) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 std::string Scope::pickUniqueAnonymousName() const {
     static size_t sNextID = 0;
 
diff --git a/Scope.h b/Scope.h
index 326ee01..c22392c 100644
--- a/Scope.h
+++ b/Scope.h
@@ -45,6 +45,7 @@
     Interface *getInterface() const;
 
     bool containsSingleInterface(std::string *ifaceName) const;
+    bool containsInterfaces() const;
 
     std::string pickUniqueAnonymousName() const;
 
diff --git a/Type.cpp b/Type.cpp
index e42f072..e54fdc5 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -16,6 +16,7 @@
 
 #include "Type.h"
 
+#include "Annotation.h"
 #include "ScalarType.h"
 
 #include <hidl-util/Formatter.h>
@@ -23,9 +24,20 @@
 
 namespace android {
 
-Type::Type() {}
+Type::Type()
+    : mAnnotations(nullptr) {
+}
+
 Type::~Type() {}
 
+void Type::setAnnotations(std::vector<Annotation *> *annotations) {
+    mAnnotations = annotations;
+}
+
+const std::vector<Annotation *> &Type::annotations() const {
+    return *mAnnotations;
+}
+
 bool Type::isScope() const {
     return false;
 }
diff --git a/Type.h b/Type.h
index 6322207..5a82718 100644
--- a/Type.h
+++ b/Type.h
@@ -21,10 +21,12 @@
 #include <android-base/macros.h>
 #include <string>
 #include <utils/Errors.h>
+#include <vector>
 #include <set>
 
 namespace android {
 
+struct Annotation;
 struct Formatter;
 struct ScalarType;
 struct FQName;
@@ -158,6 +160,9 @@
 
     virtual void getAlignmentAndSize(size_t *align, size_t *size) const;
 
+    void setAnnotations(std::vector<Annotation *> *annotations);
+    const std::vector<Annotation *> &annotations() const;
+
 protected:
     void handleError(Formatter &out, ErrorMode mode) const;
     void handleError2(Formatter &out, ErrorMode mode) const;
@@ -184,6 +189,8 @@
             const std::string &extra) const;
 
 private:
+    std::vector<Annotation *> *mAnnotations;
+
     DISALLOW_COPY_AND_ASSIGN(Type);
 };
 
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 08ac6f0..0e7483e 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -105,6 +105,9 @@
 %type<type> enum_declaration
 %type<type> struct_or_union_declaration
 %type<type> opt_extends
+%type<type> type_declaration_body interface_declaration typedef_declaration
+%type<type> named_struct_or_union_declaration named_enum_declaration
+%type<type> compound_declaration annotated_compound_declaration
 
 %type<field> field_declaration
 %type<fields> field_declarations struct_or_union_body
@@ -329,41 +332,7 @@
     | EXTENDS fqtype { $$ = $2; }
 
 body
-    : opt_annotations INTERFACE IDENTIFIER opt_extends
-      {
-          if ($4 != NULL && !$4->isInterface()) {
-              std::cerr << "ERROR: You can only extend interfaces. at" << @4
-                        << "\n";
-
-              YYERROR;
-          }
-
-          if ($3[0] != 'I') {
-              std::cerr << "ERROR: All interface names must start with an 'I' "
-                        << "prefix. at " << @3 << "\n";
-
-              YYERROR;
-          }
-
-          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(iface, &errorMsg)) {
-              std::cerr << "ERROR: " << errorMsg << " at " << @3 << "\n";
-              YYERROR;
-          }
-
-          ast->enterScope(iface);
-      }
-      '{' interface_declarations '}' ';'
-      {
-          Interface *iface = static_cast<Interface *>(ast->scope());
-
-          ast->leaveScope();
-      }
-    | type_declarations
+    : type_declarations
     ;
 
 interface_declarations
@@ -382,9 +351,66 @@
     ;
 
 type_declaration
+    : opt_annotations type_declaration_body
+      {
+          if ($2 != nullptr) {
+              $2->setAnnotations($1);
+          } else if (!$1->empty()) {
+              // Since typedefs are always resolved to their target it makes
+              // little sense to annotate them and have their annotations
+              // impose semantics other than their target type.
+              std::cerr << "ERROR: typedefs cannot be annotated. at " << @2
+                        << "\n";
+
+              YYERROR;
+          }
+      }
+    ;
+
+type_declaration_body
     : named_struct_or_union_declaration ';'
     | named_enum_declaration ';'
     | typedef_declaration ';'
+    | interface_declaration ';'
+    ;
+
+interface_declaration
+    : INTERFACE IDENTIFIER opt_extends
+      {
+          if ($3 != NULL && !$3->isInterface()) {
+              std::cerr << "ERROR: You can only extend interfaces. at" << @3
+                        << "\n";
+
+              YYERROR;
+          }
+
+          if ($2[0] != 'I') {
+              std::cerr << "ERROR: All interface names must start with an 'I' "
+                        << "prefix. at " << @2 << "\n";
+
+              YYERROR;
+          }
+
+          Interface *iface = new Interface($2, static_cast<Interface *>($3));
+
+          // Register interface immediately so it can be referenced inside
+          // definition.
+          std::string errorMsg;
+          if (!ast->addScopedType(iface, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
+              YYERROR;
+          }
+
+          ast->enterScope(iface);
+      }
+      '{' interface_declarations '}'
+      {
+          Interface *iface = static_cast<Interface *>(ast->scope());
+
+          ast->leaveScope();
+
+          $$ = iface;
+      }
     ;
 
 typedef_declaration
@@ -395,6 +421,8 @@
               std::cerr << "ERROR: " << errorMsg << " at " << @3 << "\n";
               YYERROR;
           }
+
+          $$ = nullptr;
       }
     ;
 
@@ -525,6 +553,8 @@
               std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
+
+          $$ = container;
       }
     ;
 
@@ -580,8 +610,20 @@
 
 field_declaration
     : type IDENTIFIER ';' { $$ = new CompoundField($2, $1); }
-    | struct_or_union_declaration ';' { $$ = NULL; }
-    | enum_declaration ';' { $$ = NULL; }
+    | annotated_compound_declaration ';' { $$ = NULL; }
+    ;
+
+annotated_compound_declaration
+    : opt_annotations compound_declaration
+      {
+          $2->setAnnotations($1);
+          $$ = $2;
+      }
+    ;
+
+compound_declaration
+    : struct_or_union_declaration { $$ = $1; }
+    | enum_declaration { $$ = $1; }
     ;
 
 opt_storage_type
@@ -619,6 +661,8 @@
               std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
+
+          $$ = enumType;
       }
     ;
 
@@ -712,8 +756,7 @@
 
           $$ = new VectorType($3);
       }
-    | struct_or_union_declaration { $$ = $1; }
-    | enum_declaration { $$ = $1; }
+    | annotated_compound_declaration { $$ = $1; }
     | INTERFACE { $$ = new GenericBinder; }
     ;