Structured Parcelables: int/string default values.

Initial two types for defaults.

Syntax is:
parcelable MyParcelable {
    String name = "wicked";
    int rest = 0;
}

Bug: 110758329
Test: runtests.sh
Change-Id: Ieadf503ccb9acedf6782c15964c2d4957549542d
diff --git a/aidl.cpp b/aidl.cpp
index f859b1d..d8cc4b8 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -171,6 +171,10 @@
                 TypeNamespace* types) {
   int err = 0;
   for (const auto& v : parcel->GetFields()) {
+    if (!v->CheckValid()) {
+      err = 1;
+    }
+
     if (!types->MaybeAddContainerType(v->GetType())) {
       err = 1;  // return type is invalid
     }
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 4cb3aa7..5ca18d1 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -142,10 +142,32 @@
 
 AidlVariableDeclaration::AidlVariableDeclaration(AidlTypeSpecifier* type, std::string name,
                                                  unsigned line)
-    : type_(type), name_(name), line_(line) {}
+    : AidlVariableDeclaration(type, name, line, nullptr /*default_value*/) {}
+
+AidlVariableDeclaration::AidlVariableDeclaration(AidlTypeSpecifier* type, std::string name,
+                                                 unsigned line, AidlConstantValue* default_value)
+    : type_(type), name_(name), line_(line), default_value_(default_value) {}
+
+bool AidlVariableDeclaration::CheckValid() const {
+  if (default_value_ == nullptr) return true;
+
+  const string given_type = type_->GetName();
+  const string value_type = AidlConstantValue::ToString(default_value_->GetType());
+
+  if (given_type != value_type) {
+    cerr << "Declaration " << name_ << " is of type " << given_type << " but value is of type "
+         << value_type << " on line " << line_ << endl;
+    return false;
+  }
+  return true;
+}
 
 string AidlVariableDeclaration::ToString() const {
-  return type_->ToString() + " " + name_;
+  string ret = type_->ToString() + " " + name_;
+  if (default_value_ != nullptr) {
+    ret += " = " + default_value_->ToString();
+  }
+  return ret;
 }
 
 string AidlVariableDeclaration::Signature() const {
diff --git a/aidl_language.h b/aidl_language.h
index 19679e3..374ff6f 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -151,16 +151,22 @@
   DISALLOW_COPY_AND_ASSIGN(AidlTypeSpecifier);
 };
 
+class AidlConstantValue;
 class AidlVariableDeclaration : public AidlNode {
  public:
   AidlVariableDeclaration(AidlTypeSpecifier* type, std::string name, unsigned line);
+  AidlVariableDeclaration(AidlTypeSpecifier* type, std::string name, unsigned line,
+                          AidlConstantValue* default_value);
   virtual ~AidlVariableDeclaration() = default;
 
   std::string GetName() const { return name_; }
   int GetLine() const { return line_; }
   const AidlTypeSpecifier& GetType() const { return *type_; }
+  const AidlConstantValue* GetDefaultValue() const { return default_value_.get(); }
+
   AidlTypeSpecifier* GetMutableType() { return type_.get(); }
 
+  bool CheckValid() const;
   std::string ToString() const;
   std::string Signature() const;
 
@@ -168,6 +174,7 @@
   std::unique_ptr<AidlTypeSpecifier> type_;
   std::string name_;
   unsigned line_;
+  std::unique_ptr<AidlConstantValue> default_value_;
 
   DISALLOW_COPY_AND_ASSIGN(AidlVariableDeclaration);
 };
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index f0d34a0..21c174e 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -199,6 +199,9 @@
  : type identifier ';' {
    $$ = new AidlVariableDeclaration($1, $2->GetText(), @2.begin.line);
  }
+ | type identifier '=' constant_value ';' {
+   $$ = new AidlVariableDeclaration($1, $2->GetText(), @2.begin.line, $4);
+ }
  | error ';' {
    ps->AddError();
    $$ = nullptr;
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 0fa4291..e74ec40 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -865,9 +865,16 @@
 
   for (const auto& variable : parcel.GetFields()) {
     const Type* type = variable->GetType().GetLanguageType<Type>();
+    const AidlConstantValue* default_value = variable->GetDefaultValue();
 
-    parcel_class->AddPublic(std::unique_ptr<LiteralDecl>(new LiteralDecl(
-        StringPrintf("%s %s;\n", type->CppType().c_str(), variable->GetName().c_str()))));
+    std::ostringstream out;
+    out << type->CppType().c_str() << " " << variable->GetName().c_str();
+    if (default_value) {
+      out << " = " << type->CppType().c_str() << "(" << default_value->ToString() << ")";
+    }
+    out << ";\n";
+
+    parcel_class->AddPublic(std::unique_ptr<LiteralDecl>(new LiteralDecl(out.str())));
   }
 
   unique_ptr<MethodDecl> read(new MethodDecl(kAndroidStatusLiteral, "readFromParcel",
diff --git a/generate_java.cpp b/generate_java.cpp
index 5f5472e..30951a8 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -113,9 +113,16 @@
 
   for (const auto& variable : parcel->GetFields()) {
     const Type* type = variable->GetType().GetLanguageType<Type>();
-    Variable* variable_element =
-        new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
-    parcel_class->elements.push_back(new Field(PUBLIC, variable_element));
+    const AidlConstantValue* default_value = variable->GetDefaultValue();
+
+    std::ostringstream out;
+    out << "public " << type->JavaType() << (variable->GetType().IsArray() ? "[]" : "") << " "
+        << variable->GetName();
+    if (default_value) {
+      out << " = " << default_value->ToString();
+    }
+    out << ";\n";
+    parcel_class->elements.push_back(new LiteralClassElement(out.str()));
   }
 
   std::ostringstream out;
diff --git a/tests/aidl_test_client_parcelables.cpp b/tests/aidl_test_client_parcelables.cpp
index 66b66c0..75d5fb0 100644
--- a/tests/aidl_test_client_parcelables.cpp
+++ b/tests/aidl_test_client_parcelables.cpp
@@ -151,6 +151,15 @@
   StructuredParcelable parcelable;
   parcelable.f = kDesiredValue;
 
+  if (parcelable.stringDefaultsToFoo != String16("foo")) {
+    cout << "stringDefaultsToFoo should be 'foo' but is " << parcelable.stringDefaultsToFoo;
+    return false;
+  }
+  if (parcelable.intDefaultsToFive != 5) {
+    cout << "intDefaultsToFive should be 5 but is " << parcelable.intDefaultsToFive;
+    return false;
+  }
+
   s->FillOutStructuredParcelable(&parcelable);
 
   if (parcelable.shouldContainThreeFs.size() != 3) {
@@ -167,7 +176,7 @@
   }
 
   if (parcelable.shouldBeJerry != "Jerry") {
-    cout << "shouldBeJerry is not Jerry and is instead " << parcelable.shouldBeJerry << endl;
+    cout << "shouldBeJerry should be 'Jerry' but is " << parcelable.shouldBeJerry << endl;
     return false;
   }
 
diff --git a/tests/android/aidl/tests/StructuredParcelable.aidl b/tests/android/aidl/tests/StructuredParcelable.aidl
index bc23eb6..60bb579 100644
--- a/tests/android/aidl/tests/StructuredParcelable.aidl
+++ b/tests/android/aidl/tests/StructuredParcelable.aidl
@@ -20,4 +20,7 @@
     int[] shouldContainThreeFs;
     int f;
     @utf8InCpp String shouldBeJerry;
+
+    String stringDefaultsToFoo = "foo";
+    int intDefaultsToFive = 5;
 }
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index 4795c1d..4826354 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -708,6 +708,14 @@
       parcelable.f = kDesiredFValue;
       parcelable.shouldBeJerry = "";
 
+      if (!parcelable.stringDefaultsToFoo.equals("foo")) {
+        mLog.logAndThrow(
+            "stringDefaultsToFoo should be 'foo' but is " + parcelable.stringDefaultsToFoo);
+      }
+      if (parcelable.intDefaultsToFive != 5) {
+        mLog.logAndThrow("intDefaultsToFive should be 5 but is " + parcelable.intDefaultsToFive);
+      }
+
       try {
         service.FillOutStructuredParcelable(parcelable);
       } catch (RemoteException ex) {