Support initialization of constant array exports.

BUG=5901034

Change-Id: Ibdc74323080518223bbf79caef0c91030c501f17
diff --git a/slang_rs_export_var.cpp b/slang_rs_export_var.cpp
index e5b4b3a..56e256f 100644
--- a/slang_rs_export_var.cpp
+++ b/slang_rs_export_var.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010, The Android Open Source Project
+ * Copyright 2010-2012, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,19 +20,33 @@
 
 #include "llvm/ADT/APSInt.h"
 
-#include "slang_assert.h"
 #include "slang_rs_context.h"
 #include "slang_rs_export_type.h"
 
 namespace slang {
 
+namespace {
+
+static clang::DiagnosticBuilder ReportVarError(RSContext *Context,
+                           const clang::SourceLocation Loc,
+                           const char *Message) {
+  clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
+  const clang::SourceManager *SM = Context->getSourceManager();
+  return DiagEngine->Report(clang::FullSourceLoc(Loc, *SM),
+      DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, Message));
+}
+
+}  // namespace
+
 RSExportVar::RSExportVar(RSContext *Context,
                          const clang::VarDecl *VD,
                          const RSExportType *ET)
     : RSExportable(Context, RSExportable::EX_VAR),
       mName(VD->getName().data(), VD->getName().size()),
       mET(ET),
-      mIsConst(false) {
+      mIsConst(false),
+      mArraySize(0),
+      mNumInits(0) {
   // mInit - Evaluate initializer expression
   const clang::Expr *Initializer = VD->getAnyInitializer();
   if (Initializer != NULL) {
@@ -43,22 +57,47 @@
         break;
       }
       case RSExportType::ExportClassPointer: {
-        if (Initializer->isNullPointerConstant
-            (Context->getASTContext(),
-             clang::Expr::NPC_ValueDependentIsNotNull)
-            )
+        if (Initializer->isNullPointerConstant(Context->getASTContext(),
+                clang::Expr::NPC_ValueDependentIsNotNull)) {
           mInit.Val = clang::APValue(llvm::APSInt(1));
-        else
-          Initializer->EvaluateAsRValue(mInit, Context->getASTContext());
+        } else {
+          if (!Initializer->EvaluateAsRValue(mInit, Context->getASTContext())) {
+            ReportVarError(Context, Initializer->getExprLoc(),
+                           "initializer is not an R-value");
+          }
+        }
         break;
       }
+      case RSExportType::ExportClassConstantArray: {
+        const clang::InitListExpr *IList = 
+            static_cast<const clang::InitListExpr*>(Initializer);
+        if (!IList) {
+          ReportVarError(Context, VD->getLocation(),
+                         "Unable to find initializer list");
+          break;
+        }
+        const RSExportConstantArrayType *ECAT =
+            static_cast<const RSExportConstantArrayType*>(ET);
+        mArraySize = ECAT->getSize();
+        mNumInits = IList->getNumInits();
+        for (unsigned int i = 0; i < mNumInits; i++) {
+          clang::Expr::EvalResult tempInit;
+          if (!IList->getInit(i)->EvaluateAsRValue(tempInit,
+                                                   Context->getASTContext())) {
+            ReportVarError(Context, IList->getInit(i)->getExprLoc(),
+                           "initializer is not an R-value");
+          }
+          mInitArray.push_back(tempInit);
+        }
+        break;
+      }
+      case RSExportType::ExportClassMatrix:
       case RSExportType::ExportClassRecord: {
-        // No action
-        fprintf(stderr, "RSExportVar::RSExportVar : Reflection of initializer "
-                        "to variable '%s' (of type '%s') is unsupported "
-                        "currently.\n",
-                mName.c_str(),
-                ET->getName().c_str());
+        ReportVarError(Context, VD->getLocation(),
+                       "Reflection of initializer to variable '%0' (of type "
+                       "'%1') is unsupported currently.")
+            << mName
+            << ET->getName();
         break;
       }
       default: {
diff --git a/slang_rs_export_var.h b/slang_rs_export_var.h
index 61d997a..221551f 100644
--- a/slang_rs_export_var.h
+++ b/slang_rs_export_var.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010, The Android Open Source Project
+ * Copyright 2010-2012, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
 
 #include "llvm/ADT/StringRef.h"
 
+#include "slang_assert.h"
 #include "slang_rs_exportable.h"
 
 namespace clang {
@@ -43,6 +44,10 @@
 
   clang::Expr::EvalResult mInit;
 
+  size_t mArraySize;
+  size_t mNumInits;
+  llvm::SmallVector<clang::Expr::EvalResult, 0> mInitArray;
+
   RSExportVar(RSContext *Context,
               const clang::VarDecl *VD,
               const RSExportType *ET);
@@ -53,6 +58,13 @@
   inline bool isConst() const { return mIsConst; }
 
   inline const clang::APValue &getInit() const { return mInit.Val; }
+
+  inline size_t getArraySize() const { return mArraySize; }
+  inline size_t getNumInits() const { return mNumInits; }
+  inline const clang::APValue &getInitArray(unsigned int i) const {
+    slangAssert(i < mNumInits);
+    return mInitArray[i].Val;
+  }
 };  // RSExportVar
 
 }   // namespace slang
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index df0906e..a6f897a 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011, The Android Open Source Project
+ * Copyright 2010-2012, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include <cctype>
 
 #include <algorithm>
+#include <sstream>
 #include <string>
 #include <utility>
 
@@ -319,7 +320,7 @@
   return NULL;
 }
 
-static std::string GetTypeName(const RSExportType *ET) {
+static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) {
   switch (ET->getClass()) {
     case RSExportType::ExportClassPrimitive: {
       return GetPrimitiveTypeName(
@@ -344,7 +345,9 @@
       const RSExportConstantArrayType* CAT =
           static_cast<const RSExportConstantArrayType*>(ET);
       std::string ElementTypeName = GetTypeName(CAT->getElementType());
-      ElementTypeName.append("[]");
+      if (Brackets) {
+        ElementTypeName.append("[]");
+      }
       return ElementTypeName;
     }
     case RSExportType::ExportClassRecord: {
@@ -667,8 +670,23 @@
        I != E;
        I++) {
     const RSExportVar *EV = *I;
-    if (!EV->getInit().isUninit())
+    if (!EV->getInit().isUninit()) {
       genInitExportVariable(C, EV->getType(), EV->getName(), EV->getInit());
+    } else if (EV->getArraySize()) {
+      // Always create an initial zero-init array object.
+      C.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = new "
+                 << GetTypeName(EV->getType(), false) << "["
+                 << EV->getArraySize() << "];" << std::endl;
+      size_t NumInits = EV->getNumInits();
+      const RSExportConstantArrayType *ECAT =
+          static_cast<const RSExportConstantArrayType*>(EV->getType());
+      const RSExportType *ET = ECAT->getElementType();
+      for (size_t i = 0; i < NumInits; i++) {
+        std::stringstream Name;
+        Name << EV->getName() << "[" << i << "]";
+        genInitExportVariable(C, ET, Name.str(), EV->getInitArray(i));
+      }
+    }
   }
 
   for (RSContext::const_export_foreach_iterator
diff --git a/tests/F_global_init/global_init.rs b/tests/F_global_init/global_init.rs
new file mode 100644
index 0000000..8d35184
--- /dev/null
+++ b/tests/F_global_init/global_init.rs
@@ -0,0 +1,20 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int ia[4] = {0, 1};
+int i = 2;
+int2 i2 = {3, 4};
+float fa[4] = {0.0, 1.0, 2.9999};
+char ca[2] = {'a', 7};
+bool ba[2] = {false, true};
+
+const int ic = 99;
+
+int ica[2] = {ic, 1000};
+
+struct s {
+    int i;
+};
+
+struct s myS = {9};
+
diff --git a/tests/F_global_init/stderr.txt.expect b/tests/F_global_init/stderr.txt.expect
new file mode 100644
index 0000000..19360f4
--- /dev/null
+++ b/tests/F_global_init/stderr.txt.expect
@@ -0,0 +1 @@
+global_init.rs:19:10: error: Reflection of initializer to variable 'myS' (of type 's') is unsupported currently.
diff --git a/tests/F_global_init/stdout.txt.expect b/tests/F_global_init/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_global_init/stdout.txt.expect
diff --git a/tests/P_array_init/array_init.rs b/tests/P_array_init/array_init.rs
new file mode 100644
index 0000000..b64e6ea
--- /dev/null
+++ b/tests/P_array_init/array_init.rs
@@ -0,0 +1,16 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+const int ic = 99;
+
+int ica[2] = {ic, 1000};
+
+float fa[4] = {1.0, 9.9999f};
+double da[2] = {7.0, 8.88888};
+char ca[4] = {'a', 7, 'b', 'c'};
+short sa[4] = {1, 1, 2, 3};
+int ia[4] = {5, 8};
+long la[2] = {13, 21};
+long long lla[4] = {34};
+bool ba[3] = {true, false};
+
diff --git a/tests/P_array_init/stderr.txt.expect b/tests/P_array_init/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_array_init/stderr.txt.expect
diff --git a/tests/P_array_init/stdout.txt.expect b/tests/P_array_init/stdout.txt.expect
new file mode 100644
index 0000000..e306a86
--- /dev/null
+++ b/tests/P_array_init/stdout.txt.expect
@@ -0,0 +1 @@
+Generating ScriptC_array_init.java ...