Interface methods can now be annotated.

The syntax is a strict subset of what Java supports. The following are valid
annotations:

@Fragile
@LotsOfStuff(single="yes", many={"a", "b", "c"})

An annotation either has no parameters (in which case the name is NOT followed
by parentheses) or is does and what follows the name is a parenthesized list
of name=value pairs, where each value is either a single quoted string literal
or a list of quoted string literals surrounded by curly braces.

Change-Id: I3c51d771b7d55c8d16531286d011f61be700a21c
diff --git a/AST.h b/AST.h
index 2f76f3d..0a1eea6 100644
--- a/AST.h
+++ b/AST.h
@@ -5,6 +5,8 @@
 #include <android-base/macros.h>
 #include <set>
 #include <string>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
 #include <utils/Vector.h>
 
 #include "FQName.h"
diff --git a/Android.mk b/Android.mk
index 7ebd2f3..724ce81 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,6 +6,7 @@
 LOCAL_IS_HOST_MODULE := true
 
 LOCAL_SRC_FILES :=              \
+    Annotation.cpp              \
     ArrayType.cpp               \
     CompoundType.cpp            \
     Constant.cpp                \
diff --git a/Annotation.cpp b/Annotation.cpp
new file mode 100644
index 0000000..d5692cf
--- /dev/null
+++ b/Annotation.cpp
@@ -0,0 +1,61 @@
+#include "Annotation.h"
+
+#include "Formatter.h"
+
+#include <vector>
+
+namespace android {
+
+Annotation::Annotation(
+        const char *name,
+        KeyedVector<std::string, std::vector<std::string> *> *params)
+    : mName(name),
+      mParamsByName(params) {
+}
+
+std::string Annotation::name() const {
+    return mName;
+}
+
+void Annotation::dump(Formatter &out) const {
+    out << "@" << mName;
+
+    if (mParamsByName->size() == 0) {
+        return;
+    }
+
+    out << "(";
+
+    for (size_t i = 0; i < mParamsByName->size(); ++i) {
+        if (i > 0) {
+            out << ", ";
+        }
+
+        out << mParamsByName->keyAt(i) << "=";
+
+        const std::vector<std::string> *param = mParamsByName->valueAt(i);
+        if (param->size() > 1) {
+            out << "{";
+        }
+
+        bool first = true;
+        for (const auto &value : *param) {
+            if (!first) {
+                out << ", ";
+            }
+
+            out << value;
+
+            first = false;
+        }
+
+        if (param->size() > 1) {
+            out << "}";
+        }
+    }
+
+    out << ")";
+}
+
+}  // namespace android
+
diff --git a/Annotation.h b/Annotation.h
new file mode 100644
index 0000000..ad98bf9
--- /dev/null
+++ b/Annotation.h
@@ -0,0 +1,32 @@
+#ifndef ANNOTATION_H_
+
+#define ANNOTATION_H_
+
+#include <android-base/macros.h>
+
+#include <string>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct Formatter;
+
+struct Annotation {
+    Annotation(
+            const char *name,
+            KeyedVector<std::string, std::vector<std::string> *> *params);
+
+    std::string name() const;
+
+    void dump(Formatter &out) const;
+
+private:
+    std::string mName;
+    KeyedVector<std::string, std::vector<std::string> *> *mParamsByName;
+
+    DISALLOW_COPY_AND_ASSIGN(Annotation);
+};
+
+}  // namespace android
+
+#endif  // ANNOTATION_H_
diff --git a/Method.cpp b/Method.cpp
index 7e0058f..2569701 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -1,17 +1,19 @@
 #include "Method.h"
 
+#include "Annotation.h"
 #include "Formatter.h"
 #include "Type.h"
 
 namespace android {
 
-Method::Method(
-        const char *name,
-        std::vector<TypedVar *> *args,
-        std::vector<TypedVar *> *results)
+Method::Method(const char *name,
+       std::vector<TypedVar *> *args,
+       std::vector<TypedVar *> *results,
+       KeyedVector<std::string, Annotation *> *annotations)
     : mName(name),
       mArgs(args),
-      mResults(results) {
+      mResults(results),
+      mAnnotationsByName(annotations) {
 }
 
 std::string Method::name() const {
@@ -26,6 +28,10 @@
     return *mResults;
 }
 
+const KeyedVector<std::string, Annotation *> &Method::annotations() const {
+    return *mAnnotationsByName;
+}
+
 // static
 std::string Method::GetSignature(const std::vector<TypedVar *> &args) {
     bool first = true;
@@ -47,6 +53,21 @@
     return out;
 }
 
+void Method::dumpAnnotations(Formatter &out) const {
+    if (mAnnotationsByName->size() == 0) {
+        return;
+    }
+
+    out << "// ";
+    for (size_t i = 0; i < mAnnotationsByName->size(); ++i) {
+        if (i > 0) {
+            out << " ";
+        }
+        mAnnotationsByName->valueAt(i)->dump(out);
+    }
+    out << "\n";
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 TypedVar::TypedVar(const char *name, Type *type)
diff --git a/Method.h b/Method.h
index a4e13d4..86c8f50 100644
--- a/Method.h
+++ b/Method.h
@@ -4,10 +4,12 @@
 
 #include <android-base/macros.h>
 #include <string>
+#include <utils/KeyedVector.h>
 #include <vector>
 
 namespace android {
 
+struct Annotation;
 struct Formatter;
 struct Type;
 struct TypedVar;
@@ -15,18 +17,23 @@
 struct Method {
     Method(const char *name,
            std::vector<TypedVar *> *args,
-           std::vector<TypedVar *> *results = NULL);
+           std::vector<TypedVar *> *results,
+           KeyedVector<std::string, Annotation *> *annotations);
 
     std::string name() const;
     const std::vector<TypedVar *> &args() const;
     const std::vector<TypedVar *> &results() const;
+    const KeyedVector<std::string, Annotation *> &annotations() const;
 
     static std::string GetSignature(const std::vector<TypedVar *> &args);
 
+    void dumpAnnotations(Formatter &out) const;
+
 private:
     std::string mName;
     std::vector<TypedVar *> *mArgs;
     std::vector<TypedVar *> *mResults;
+    KeyedVector<std::string, Annotation *> *mAnnotationsByName;
 
     DISALLOW_COPY_AND_ASSIGN(Method);
 };
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 8e6da68..f871fd8 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -237,6 +237,8 @@
         for (const auto &method : iface->methods()) {
             const bool returnsValue = !method->results().empty();
 
+            method->dumpAnnotations(out);
+
             out << "virtual ::android::hardware::Status "
                 << method->name()
                 << "("
diff --git a/hidl-gen_l.ll b/hidl-gen_l.ll
index 13ab222..359c351 100644
--- a/hidl-gen_l.ll
+++ b/hidl-gen_l.ll
@@ -13,6 +13,7 @@
 
 %{
 
+#include "Annotation.h"
 #include "AST.h"
 #include "CompoundType.h"
 #include "EnumType.h"
@@ -92,6 +93,7 @@
 "."			{ count(yyg); return('.'); }
 "="			{ count(yyg); return('='); }
 "+"			{ count(yyg); return('+'); }
+"@"			{ count(yyg); return('@'); }
 
 {PATH}{VERSION}?"::"{PATH}      { count(yyg); yylval->str = strdup(yytext); return FQNAME; }
 {VERSION}"::"{PATH}             { count(yyg); yylval->str = strdup(yytext); return FQNAME; }
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 4f640ce..0b1cd90 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -1,5 +1,6 @@
 %{
 
+#include "Annotation.h"
 #include "AST.h"
 #include "ArrayType.h"
 #include "CompoundType.h"
@@ -69,6 +70,11 @@
 %type<typedVar> typed_var
 %type<method> method_declaration
 %type<compoundStyle> struct_or_union_keyword
+%type<stringVec> annotation_string_values annotation_value
+%type<annotationParam> annotation_param
+%type<annotationParams> opt_annotation_params annotation_params
+%type<annotation> annotation
+%type<annotations> opt_annotations
 
 %start program
 
@@ -84,11 +90,87 @@
     std::vector<android::TypedVar *> *typedVars;
     android::Method *method;
     android::CompoundType::Style compoundStyle;
-    android::Vector<std::string> *stringVec;
+    std::vector<std::string> *stringVec;
+    std::pair<std::string, std::vector<std::string> *> *annotationParam;
+    android::KeyedVector<std::string, std::vector<std::string> *> *annotationParams;
+    android::Annotation *annotation;
+    android::KeyedVector<std::string, android::Annotation *> *annotations;
 }
 
 %%
 
+opt_annotations
+    : /* empty */
+      {
+          $$ = new KeyedVector<std::string, Annotation *>;
+      }
+    | opt_annotations annotation
+      {
+          $$ = $1;
+          $$->add($2->name(), $2);
+      }
+    ;
+
+annotation
+    : '@' IDENTIFIER opt_annotation_params
+      {
+          $$ = new Annotation($2, $3);
+      }
+    ;
+
+opt_annotation_params
+    : /* empty */
+      {
+          $$ = new KeyedVector<std::string, std::vector<std::string> *>;
+      }
+    | '(' annotation_params ')'
+      {
+          $$ = $2;
+      }
+    ;
+
+annotation_params
+    : annotation_param
+      {
+          $$ = new KeyedVector<std::string, std::vector<std::string> *>;
+          $$->add($1->first, $1->second);
+      }
+    | annotation_params ',' annotation_param
+      {
+          $$ = $1;
+          $$->add($3->first, $3->second);
+      }
+    ;
+
+annotation_param
+    : IDENTIFIER '=' annotation_value
+      {
+          $$ = new std::pair<std::string, std::vector<std::string> *>($1, $3);
+      }
+    ;
+
+annotation_value
+    : STRING_LITERAL
+      {
+          $$ = new std::vector<std::string>;
+          $$->push_back($1);
+      }
+    | '{' annotation_string_values '}' { $$ = $2; }
+    ;
+
+annotation_string_values
+    : STRING_LITERAL
+      {
+          $$ = new std::vector<std::string>;
+          $$->push_back($1);
+      }
+    | annotation_string_values ',' STRING_LITERAL
+      {
+          $$ = $1;
+          $$->push_back($3);
+      }
+    ;
+
 program
     : package imports body
     ;
@@ -226,13 +308,13 @@
     ;
 
 method_declaration
-    : IDENTIFIER '(' typed_vars ')' ';'
+    : opt_annotations IDENTIFIER '(' typed_vars ')' ';'
       {
-          $$ = new Method($1, $3, new std::vector<TypedVar *>);
+          $$ = new Method($2, $4, new std::vector<TypedVar *>, $1);
       }
-    | IDENTIFIER '(' typed_vars ')' GENERATES '(' typed_vars ')' ';'
+    | opt_annotations IDENTIFIER '(' typed_vars ')' GENERATES '(' typed_vars ')' ';'
       {
-          $$ = new Method($1, $3, $7);
+          $$ = new Method($2, $4, $8, $1);
       }
     ;