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;
}