AAPT2: Separate out the various steps

An early refactor. Some ideas became clearer as
development continued. Now the various phases are much
clearer and more easily reusable.

Also added a ton of tests!

Change-Id: Ic8f0a70c8222370352e63533b329c40457c0903e
diff --git a/tools/aapt2/JavaClassGenerator.cpp b/tools/aapt2/JavaClassGenerator.cpp
index e2ffe79..84a4125 100644
--- a/tools/aapt2/JavaClassGenerator.cpp
+++ b/tools/aapt2/JavaClassGenerator.cpp
@@ -19,7 +19,7 @@
 #include "Resource.h"
 #include "ResourceTable.h"
 #include "ResourceValues.h"
-#include "StringPiece.h"
+#include "util/StringPiece.h"
 
 #include <algorithm>
 #include <ostream>
@@ -32,21 +32,18 @@
 // The number of attributes to emit per line in a Styleable array.
 constexpr size_t kAttribsPerLine = 4;
 
-JavaClassGenerator::JavaClassGenerator(const std::shared_ptr<const ResourceTable>& table,
-                                       Options options) :
+JavaClassGenerator::JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options) :
         mTable(table), mOptions(options) {
 }
 
-static void generateHeader(std::ostream& out, const StringPiece16& package) {
-    out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
-           " *\n"
-           " * This class was automatically generated by the\n"
-           " * aapt tool from the resource data it found. It\n"
-           " * should not be modified by hand.\n"
-           " */\n\n";
-    out << "package " << package << ";"
-        << std::endl
-        << std::endl;
+static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) {
+    *out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+            " *\n"
+            " * This class was automatically generated by the\n"
+            " * aapt tool from the resource data it found. It\n"
+            " * should not be modified by hand.\n"
+            " */\n\n"
+            "package " << packageNameToGenerate << ";\n\n";
 }
 
 static const std::set<StringPiece16> sJavaIdentifiers = {
@@ -80,42 +77,32 @@
     return output;
 }
 
-struct GenArgs : ValueVisitorArgs {
-    GenArgs(std::ostream* o, const std::u16string* p, std::u16string* e) :
-            out(o), package(p), entryName(e) {
-    }
-
-    std::ostream* out;
-    const std::u16string* package;
-    std::u16string* entryName;
-};
-
-void JavaClassGenerator::visit(const Styleable& styleable, ValueVisitorArgs& a) {
+void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGenerate,
+                                           const std::u16string& entryName,
+                                           const Styleable* styleable,
+                                           std::ostream* out) {
     const StringPiece finalModifier = mOptions.useFinal ? " final" : "";
-    std::ostream* out = static_cast<GenArgs&>(a).out;
-    const std::u16string* package = static_cast<GenArgs&>(a).package;
-    std::u16string* entryName = static_cast<GenArgs&>(a).entryName;
 
     // This must be sorted by resource ID.
     std::vector<std::pair<ResourceId, ResourceNameRef>> sortedAttributes;
-    sortedAttributes.reserve(styleable.entries.size());
-    for (const auto& attr : styleable.entries) {
+    sortedAttributes.reserve(styleable->entries.size());
+    for (const auto& attr : styleable->entries) {
         // If we are not encoding final attributes, the styleable entry may have no ID
         // if we are building a static library.
-        assert((!mOptions.useFinal || attr.id.isValid()) && "no ID set for Styleable entry");
-        assert(attr.name.isValid() && "no name set for Styleable entry");
-        sortedAttributes.emplace_back(attr.id, attr.name);
+        assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
+        assert(attr.name && "no name set for Styleable entry");
+        sortedAttributes.emplace_back(attr.id ? attr.id.value() : ResourceId(0), attr.name.value());
     }
     std::sort(sortedAttributes.begin(), sortedAttributes.end());
 
     // First we emit the array containing the IDs of each attribute.
     *out << "        "
-         << "public static final int[] " << transform(*entryName) << " = {";
+         << "public static final int[] " << transform(entryName) << " = {";
 
     const size_t attrCount = sortedAttributes.size();
     for (size_t i = 0; i < attrCount; i++) {
         if (i % kAttribsPerLine == 0) {
-            *out << std::endl << "            ";
+            *out << "\n            ";
         }
 
         *out << sortedAttributes[i].first;
@@ -123,44 +110,46 @@
             *out << ", ";
         }
     }
-    *out << std::endl << "        };" << std::endl;
+    *out << "\n        };\n";
 
     // Now we emit the indices into the array.
     for (size_t i = 0; i < attrCount; i++) {
         *out << "        "
              << "public static" << finalModifier
-             << " int " << transform(*entryName);
+             << " int " << transform(entryName);
 
         // We may reference IDs from other packages, so prefix the entry name with
         // the package.
         const ResourceNameRef& itemName = sortedAttributes[i].second;
-        if (itemName.package != *package) {
+        if (packageNameToGenerate != itemName.package) {
             *out << "_" << transform(itemName.package);
         }
-        *out << "_" << transform(itemName.entry) << " = " << i << ";" << std::endl;
+        *out << "_" << transform(itemName.entry) << " = " << i << ";\n";
     }
 }
 
-bool JavaClassGenerator::generateType(const std::u16string& package, size_t packageId,
-                                      const ResourceTableType& type, std::ostream& out) {
+bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate,
+                                      const ResourceTablePackage* package,
+                                      const ResourceTableType* type,
+                                      std::ostream* out) {
     const StringPiece finalModifier = mOptions.useFinal ? " final" : "";
 
     std::u16string unmangledPackage;
     std::u16string unmangledName;
-    for (const auto& entry : type.entries) {
-        ResourceId id = { packageId, type.typeId, entry->entryId };
+    for (const auto& entry : type->entries) {
+        ResourceId id = { package->id.value(), type->id.value(), entry->id.value() };
         assert(id.isValid());
 
         unmangledName = entry->name;
         if (NameMangler::unmangle(&unmangledName, &unmangledPackage)) {
             // The entry name was mangled, and we successfully unmangled it.
             // Check that we want to emit this symbol.
-            if (package != unmangledPackage) {
+            if (package->name != unmangledPackage) {
                 // Skip the entry if it doesn't belong to the package we're writing.
                 continue;
             }
         } else {
-            if (package != mTable->getPackage()) {
+            if (packageNameToGenerate != package->name) {
                 // We are processing a mangled package name,
                 // but this is a non-mangled resource.
                 continue;
@@ -168,40 +157,42 @@
         }
 
         if (!isValidSymbol(unmangledName)) {
-            ResourceNameRef resourceName = { package, type.type, unmangledName };
+            ResourceNameRef resourceName = { packageNameToGenerate, type->type, unmangledName };
             std::stringstream err;
             err << "invalid symbol name '" << resourceName << "'";
             mError = err.str();
             return false;
         }
 
-        if (type.type == ResourceType::kStyleable) {
+        if (type->type == ResourceType::kStyleable) {
             assert(!entry->values.empty());
-            entry->values.front().value->accept(*this, GenArgs{ &out, &package, &unmangledName });
+            generateStyleable(packageNameToGenerate, unmangledName, static_cast<const Styleable*>(
+                    entry->values.front().value.get()), out);
         } else {
-            out << "        " << "public static" << finalModifier
-                << " int " << transform(unmangledName) << " = " << id << ";" << std::endl;
+            *out << "        " << "public static" << finalModifier
+                 << " int " << transform(unmangledName) << " = " << id << ";\n";
         }
     }
     return true;
 }
 
-bool JavaClassGenerator::generate(const std::u16string& package, std::ostream& out) {
-    const size_t packageId = mTable->getPackageId();
+bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, std::ostream* out) {
+    generateHeader(packageNameToGenerate, out);
 
-    generateHeader(out, package);
+    *out << "public final class R {\n";
 
-    out << "public final class R {" << std::endl;
-
-    for (const auto& type : *mTable) {
-        out << "    public static final class " << type->type << " {" << std::endl;
-        if (!generateType(package, packageId, *type, out)) {
-            return false;
+    for (const auto& package : mTable->packages) {
+        for (const auto& type : package->types) {
+            *out << "    public static final class " << type->type << " {\n";
+            if (!generateType(packageNameToGenerate, package.get(), type.get(), out)) {
+                return false;
+            }
+            *out << "    }\n";
         }
-        out << "    }" << std::endl;
     }
 
-    out << "}" << std::endl;
+    *out << "}\n";
+    out->flush();
     return true;
 }