safe_union: disallow zero/single member unions.

These can't be passed between processes and aren't useful (the bare
type should be used instead).

It's needed to disallow zero member unions in order to have a default
value for hidl_o.

Bug: 116156870
Test: hidl_error_test, hidl_test, hidl_java_test
Change-Id: I4cbdfa848e774d3a5efe6f63636bdbda9eec78f2
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 3ee5b10..9c3a0a9 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -70,6 +70,12 @@
         }
     }
 
+    if (mStyle == STYLE_SAFE_UNION && mFields->size() < 2) {
+        std::cerr << "ERROR: Safe union must contain at least two types to be useful at "
+                  << location() << "\n";
+        return UNKNOWN_ERROR;
+    }
+
     status_t err = validateUniqueNames();
     if (err != OK) return err;
 
@@ -213,7 +219,6 @@
         ErrorMode mode) const {
 
     CHECK(mStyle == STYLE_SAFE_UNION);
-    if (mFields->empty()) { return; }
 
     out.block([&] {
         const auto discriminatorType = getUnionDiscriminatorType();
@@ -564,15 +569,6 @@
                             ? CompoundLayout()
                             : getCompoundAlignmentAndSize();
 
-    if (mFields->empty()) {
-        out.unindent();
-        out << "};\n\n";
-
-        emitLayoutAsserts(out, layout.overall, "");
-        out << "\n";
-        return;
-    }
-
     out << "enum class hidl_discriminator : "
         << getUnionDiscriminatorType()->getCppType(StorageMode_Stack, false)
         << " ";
@@ -818,7 +814,7 @@
             << "std::string os;\n";
         out << "os += \"{\";\n";
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "\nswitch (o.getDiscriminator()) {\n";
             out.indent();
         }
@@ -850,7 +846,7 @@
             }
         }
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "default: ";
             out.block([&] {
                 out << "details::logAlwaysFatal(\"Unknown union discriminator.\");\n";
@@ -867,7 +863,7 @@
             << getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", "
             << getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") ";
         out.block([&] {
-            if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+            if (mStyle == STYLE_SAFE_UNION) {
                 out.sIf("lhs.getDiscriminator() != rhs.getDiscriminator()", [&] {
                     out << "return false;\n";
                 }).endl();
@@ -898,7 +894,7 @@
                 }
             }
 
-            if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+            if (mStyle == STYLE_SAFE_UNION) {
                 out << "default: ";
                 out.block([&] {
                     out << "details::logAlwaysFatal(\"Unknown union discriminator.\");\n";
@@ -1184,7 +1180,6 @@
 }
 
 void CompoundType::emitSafeUnionTypeDefinitions(Formatter& out) const {
-    if (mFields->empty()) { return; }
     emitSafeUnionTypeConstructors(out);
 
     out << "void "
@@ -1306,7 +1301,7 @@
 
     Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
 
-    if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+    if (mStyle == STYLE_SAFE_UNION) {
         const std::string discriminatorStorageType = (
                 getUnionDiscriminatorType()->getJavaType(false));
 
@@ -1421,7 +1416,7 @@
             << discriminatorStorageType
             << " getDiscriminator() { return hidl_d; }\n\n";
 
-    } else if (!mFields->empty()) {
+    } else {
         for (const auto& field : *mFields) {
             field->emitDocComment(out);
 
@@ -1449,14 +1444,14 @@
             }).endl();
             out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
 
-            if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+            if (mStyle == STYLE_SAFE_UNION) {
                 out.sIf("this.hidl_d != other.hidl_d", [&] {
                     out << "return false;\n";
                 }).endl();
                 out.sIf("!android.os.HidlSupport.deepEquals(this.hidl_o, other.hidl_o)", [&] {
                     out << "return false;\n";
                 }).endl();
-            } else if (!mFields->empty()) {
+            } else {
                 for (const auto &field : *mFields) {
                     std::string condition = (field->type().isScalar() || field->type().isEnum())
                         ? "this." + field->name() + " != other." + field->name()
@@ -1474,7 +1469,7 @@
         out.block([&] {
             out << "return java.util.Objects.hash(\n";
             out.indent(2, [&] {
-                if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+                if (mStyle == STYLE_SAFE_UNION) {
                     out << "android.os.HidlSupport.deepHashCode(this.hidl_o),\n"
                         << "java.util.Objects.hashCode(this.hidl_d)";
                 } else {
@@ -1496,7 +1491,7 @@
         out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
             << "builder.append(\"{\");\n";
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "switch (this.hidl_d) {\n";
             out.indent();
         }
@@ -1527,7 +1522,7 @@
             }
         }
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "default: { throw new Error(\"Unknown union discriminator.\"); }\n";
 
             out.unindent();
@@ -1545,7 +1540,7 @@
     out.indent();
     if (containsInterface()) {
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "hidl_d = ";
             getUnionDiscriminatorType()->emitJavaReaderWriter(
                     out, "parcel", "hidl_d", true);
@@ -1572,7 +1567,7 @@
             }
         }
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "default: { throw new Error(\"Unknown union discriminator.\"); }\n";
 
             out.unindent();
@@ -1626,7 +1621,7 @@
         out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
         out.unindent();
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
                 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
                 "_hidl_offset + " + std::to_string(layout.discriminator.offset),
@@ -1664,7 +1659,7 @@
             }
         }
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "default: { throw new Error(\"Unknown union discriminator.\"); }\n";
 
             out.unindent();
@@ -1680,7 +1675,7 @@
     out.indent();
 
     if (containsInterface()) {
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             getUnionDiscriminatorType()->emitJavaReaderWriter(
                 out, "parcel", "hidl_d", false);
 
@@ -1703,7 +1698,7 @@
             }
         }
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "default: { throw new Error(\"Unknown union discriminator.\"); }\n";
 
             out.unindent();
@@ -1755,7 +1750,7 @@
         out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
         out.unindent();
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
                 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
                 "_hidl_offset + " + std::to_string(layout.discriminator.offset),
@@ -1791,7 +1786,7 @@
             }
         }
 
-        if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+        if (mStyle == STYLE_SAFE_UNION) {
             out << "default: { throw new Error(\"Unknown union discriminator.\"); }\n";
 
             out.unindent();
@@ -1836,7 +1831,7 @@
 
     out << "::android::status_t _hidl_err = ::android::OK;\n\n";
 
-    if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+    if (mStyle == STYLE_SAFE_UNION) {
         out << "switch (" << name << ".getDiscriminator()) {\n";
         out.indent();
     }
@@ -1881,7 +1876,7 @@
         }
     }
 
-    if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+    if (mStyle == STYLE_SAFE_UNION) {
         out << "default: { break; }\n";
         out.unindent();
         out << "}\n";
@@ -2137,7 +2132,7 @@
     Layout& innerStruct = compoundLayout.innerStruct;
     Layout& discriminator = compoundLayout.discriminator;
 
-    if (mStyle == STYLE_SAFE_UNION && !mFields->empty()) {
+    if (mStyle == STYLE_SAFE_UNION) {
         getUnionDiscriminatorType()->getAlignmentAndSize(
             &(discriminator.align), &(discriminator.size));