Union can be @JavaOnlyImmutable

For now it doesn't affect generated code, but it enables immutable
parcelables can have immutable unions. Upcoming change will make
generated class immutable when a union is annotated as
@JavaOnlyImmutable.

Introduced "AidlWithFields" which can handles fields of parcelable
classes(AidlStructuredParcelable and AidlUnionDeclaration).

Bug: 171637180
Test: aidl_unittests / aidl_integration_test
Change-Id: I492722eeed36e8a7e6f0eb81ef292d2caff5d624
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 0fa2dd1..0fb20b9 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -860,12 +860,60 @@
   writer->Write("parcelable %s ;\n", GetName().c_str());
 }
 
+bool AidlWithFields::CheckValid(const AidlParcelable& parcel,
+                                const AidlTypenames& typenames) const {
+  bool success = true;
+
+  for (const auto& v : GetFields()) {
+    const bool field_valid = v->CheckValid(typenames);
+    success = success && field_valid;
+  }
+
+  // field names should be unique
+  std::set<std::string> fieldnames;
+  for (const auto& v : GetFields()) {
+    bool duplicated = !fieldnames.emplace(v->GetName()).second;
+    if (duplicated) {
+      AIDL_ERROR(v) << "'" << parcel.GetName() << "' has duplicate field name '" << v->GetName()
+                    << "'";
+      success = false;
+    }
+  }
+
+  // immutable parcelables should have immutable fields.
+  if (parcel.IsJavaOnlyImmutable()) {
+    for (const auto& v : GetFields()) {
+      if (!typenames.CanBeJavaOnlyImmutable(v->GetType())) {
+        AIDL_ERROR(v) << "The @JavaOnlyImmutable '" << parcel.GetName() << "' has a "
+                      << "non-immutable field named '" << v->GetName() << "'.";
+        success = false;
+      }
+    }
+  }
+
+  return success;
+}
+
+bool AidlWithFields::CheckValidForGetterNames(const AidlParcelable& parcel) const {
+  bool success = true;
+  std::set<std::string> getters;
+  for (const auto& v : GetFields()) {
+    bool duplicated = !getters.emplace(CapitalizeFirstLetter(*v, v->GetName())).second;
+    if (duplicated) {
+      AIDL_ERROR(v) << "'" << parcel.GetName() << "' has duplicate field name '" << v->GetName()
+                    << "' after capitalizing the first letter";
+      success = false;
+    }
+  }
+  return success;
+}
+
 AidlStructuredParcelable::AidlStructuredParcelable(
     const AidlLocation& location, const std::string& name, const std::string& package,
     const std::string& comments, std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables,
     std::vector<std::string>* type_params)
     : AidlParcelable(location, name, package, comments, "" /*cpp_header*/, type_params),
-      variables_(std::move(*variables)) {}
+      AidlWithFields(variables) {}
 
 void AidlStructuredParcelable::Dump(CodeWriter* writer) const {
   DumpHeader(writer);
@@ -893,25 +941,14 @@
 }
 
 bool AidlStructuredParcelable::CheckValid(const AidlTypenames& typenames) const {
-  bool success = true;
   if (!AidlParcelable::CheckValid(typenames)) {
     return false;
   }
-
-  for (const auto& v : GetFields()) {
-    const bool field_valid = v->CheckValid(typenames);
-    success = success && field_valid;
+  if (!AidlWithFields::CheckValid(*this, typenames)) {
+    return false;
   }
 
-  std::set<std::string> fieldnames;
-  for (const auto& v : GetFields()) {
-    bool duplicated = !fieldnames.emplace(v->GetName()).second;
-    if (duplicated) {
-      AIDL_ERROR(this) << "The parcelable '" << this->GetName() << "' has duplicate field name '"
-                       << v->GetName() << "'";
-      return false;
-    }
-  }
+  bool success = true;
 
   if (IsFixedSize()) {
     for (const auto& v : GetFields()) {
@@ -924,19 +961,9 @@
   }
 
   if (IsJavaOnlyImmutable()) {
-    std::set<std::string> getters;
-    for (const auto& v : GetFields()) {
-      if (!typenames.CanBeJavaOnlyImmutable(v->GetType())) {
-        AIDL_ERROR(v) << "The @JavaOnlyImmutable parcelable '" << this->GetName() << "' has a "
-                      << "non-immutable field named '" << v->GetName() << "'.";
-        success = false;
-      }
-      bool duplicated = !getters.emplace(CapitalizeFirstLetter(*v, v->GetName())).second;
-      if (duplicated) {
-        AIDL_ERROR(this) << "The parcelable '" << this->GetName() << "' has duplicate field name '"
-                         << v->GetName() << "' after capitalizing the first letter";
-        return false;
-      }
+    // Immutable parcelables provide getters
+    if (!CheckValidForGetterNames(*this)) {
+      success = false;
     }
   }
 
@@ -1146,11 +1173,12 @@
                              std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables,
                              std::vector<std::string>* type_params)
     : AidlParcelable(location, name, package, comments, "" /*cpp_header*/, type_params),
-      variables_(std::move(*variables)) {}
+      AidlWithFields(variables) {}
 
 std::set<AidlAnnotation::Type> AidlUnionDecl::GetSupportedAnnotations() const {
   return {AidlAnnotation::Type::VINTF_STABILITY, AidlAnnotation::Type::HIDE,
-          AidlAnnotation::Type::JAVA_PASSTHROUGH, AidlAnnotation::Type::JAVA_DERIVE};
+          AidlAnnotation::Type::JAVA_PASSTHROUGH, AidlAnnotation::Type::JAVA_DERIVE,
+          AidlAnnotation::Type::JAVA_ONLY_IMMUTABLE};
 }
 
 void AidlUnionDecl::Dump(CodeWriter* writer) const {
@@ -1168,15 +1196,17 @@
 }
 
 bool AidlUnionDecl::CheckValid(const AidlTypenames& typenames) const {
-  // visit parent
+  // visit parents
   if (!AidlParcelable::CheckValid(typenames)) {
     return false;
   }
-  // visit members
-  for (const auto& v : GetFields()) {
-    if (!v->CheckValid(typenames)) {
-      return false;
-    }
+  if (!AidlWithFields::CheckValid(*this, typenames)) {
+    return false;
+  }
+
+  // unions provide getters always
+  if (!CheckValidForGetterNames(*this)) {
+    return false;
   }
 
   // now, visit self!