Enum types now emit operator| and operator|= for easier bitset manipulation.

Bug: 31702236
Change-Id: I166da2fe0019493c81151914ebabf591b705a713
Test: visual check, mma
diff --git a/EnumType.cpp b/EnumType.cpp
index 5513596..8f959e7 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -144,14 +144,15 @@
 
 status_t EnumType::emitTypeDeclarations(Formatter &out) const {
     const ScalarType *scalarType = mStorageType->resolveToScalarType();
-    CHECK(scalarType != NULL);
+    CHECK(scalarType != nullptr);
 
     std::string extra;
+    const std::string storageType = ((Type *)scalarType)->getCppType(&extra);
 
     out << "enum class "
         << localName()
         << " : "
-        << ((Type *)scalarType)->getCppType(&extra)
+        << storageType
         << " {\n";
 
     out.indent();
@@ -186,6 +187,64 @@
     return OK;
 }
 
+void EnumType::emitEnumBitwiseOrOperator(Formatter &out, bool mutating) const {
+    const ScalarType *scalarType = mStorageType->resolveToScalarType();
+    CHECK(scalarType != nullptr);
+
+    std::string extra;
+    const std::string storageType = ((Type *)scalarType)->getCppType(&extra);
+
+    out << "inline "
+        << fullName()
+        << (mutating ? " &" : "")
+        << " operator|"
+        << (mutating ? "=" : "")
+        << "(\n";
+
+    out.indent();
+    out.indent();
+
+    out << fullName()
+        << (mutating ? " &" : " ")
+        << "lhs, "
+        << fullName()
+        << " rhs) {\n";
+    out.unindent();
+
+    if (mutating) {
+        out << "lhs = ";
+    } else {
+        out << "return ";
+    }
+    out << "static_cast<"
+        << fullName()
+        << ">(\n";
+    out.indent();
+    out.indent();
+    out << "static_cast<"
+        << storageType
+        << ">(lhs) | static_cast<"
+        << storageType
+        << ">(rhs));\n";
+    out.unindent();
+    out.unindent();
+
+    if (mutating) {
+        out << "return lhs;\n";
+    }
+
+    out.unindent();
+
+    out << "}\n\n";
+}
+
+status_t EnumType::emitGlobalTypeDeclarations(Formatter &out) const {
+    emitEnumBitwiseOrOperator(out, false /* mutating */);
+    emitEnumBitwiseOrOperator(out, true /* mutating */);
+
+    return OK;
+}
+
 status_t EnumType::emitJavaTypeDeclarations(Formatter &out, bool) const {
     const ScalarType *scalarType = mStorageType->resolveToScalarType();
     CHECK(scalarType != NULL);
diff --git a/EnumType.h b/EnumType.h
index b4d0b15..e7823ef 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -72,6 +72,7 @@
             bool isReader) const override;
 
     status_t emitTypeDeclarations(Formatter &out) const override;
+    status_t emitGlobalTypeDeclarations(Formatter &out) const override;
 
     status_t emitJavaTypeDeclarations(
             Formatter &out, bool atTopLevel) const override;
@@ -90,6 +91,8 @@
     void getTypeChain(std::vector<const EnumType *> *out) const;
     const Annotation *findExportAnnotation() const;
 
+    void emitEnumBitwiseOrOperator(Formatter &out, bool mutating) const;
+
     std::vector<EnumValue *> mValues;
     Type *mStorageType;
 
diff --git a/Scope.cpp b/Scope.cpp
index 452a41f..c4d07c2 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -141,6 +141,18 @@
     return OK;
 }
 
+status_t Scope::emitGlobalTypeDeclarations(Formatter &out) const {
+    for (size_t i = 0; i < mTypes.size(); ++i) {
+        status_t err = mTypes[i]->emitGlobalTypeDeclarations(out);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
 status_t Scope::emitJavaTypeDeclarations(
         Formatter &out, bool atTopLevel) const {
     for (size_t i = 0; i < mTypes.size(); ++i) {
diff --git a/Scope.h b/Scope.h
index 08683dd..fd6074c 100644
--- a/Scope.h
+++ b/Scope.h
@@ -52,6 +52,7 @@
     std::string pickUniqueAnonymousName() const;
 
     status_t emitTypeDeclarations(Formatter &out) const override;
+    status_t emitGlobalTypeDeclarations(Formatter &out) const override;
 
     status_t emitJavaTypeDeclarations(
             Formatter &out, bool atTopLevel) const override;
diff --git a/Type.cpp b/Type.cpp
index d81eeef..eafda3a 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -321,6 +321,10 @@
     return OK;
 }
 
+status_t Type::emitGlobalTypeDeclarations(Formatter &) const {
+    return OK;
+}
+
 status_t Type::emitTypeDefinitions(
         Formatter &, const std::string) const {
     return OK;
diff --git a/Type.h b/Type.h
index f510340..04141ff 100644
--- a/Type.h
+++ b/Type.h
@@ -164,6 +164,10 @@
 
     virtual status_t emitTypeDeclarations(Formatter &out) const;
 
+    // Emit any declarations pertaining to this type that have to be
+    // at global scope, i.e. enum class operators.
+    virtual status_t emitGlobalTypeDeclarations(Formatter &out) const;
+
     virtual status_t emitTypeDefinitions(
             Formatter &out, const std::string prefix) const;
 
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 680a7b8..f8a5b1a 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -263,7 +263,13 @@
     if (isInterface) {
         out.unindent();
 
-        out << "};\n";
+        out << "};\n\n";
+    }
+
+    err = mRootScope->emitGlobalTypeDeclarations(out);
+
+    if (err != OK) {
+        return err;
     }
 
     out << "\n";