Loading tools/aapt2/Debug.cpp +9 −8 Original line number Diff line number Diff line Loading @@ -124,17 +124,18 @@ void Debug::printTable(ResourceTable* table) { } for (const ResourceEntry* entry : sortedEntries) { ResourceId id = { package->id ? package->id.value() : uint8_t(0), ResourceId id(package->id ? package->id.value() : uint8_t(0), type->id ? type->id.value() : uint8_t(0), entry->id ? entry->id.value() : uint16_t(0) }; entry->id ? entry->id.value() : uint16_t(0)); ResourceName name(package->name, type->type, entry->name); ResourceName name = { package->name, type->type, entry->name }; std::cout << " spec resource " << id << " " << name; if (entry->publicStatus.isPublic) { std::cout << " PUBLIC"; switch (entry->symbolStatus.state) { case SymbolState::kPublic: std::cout << " PUBLIC"; break; case SymbolState::kPrivate: std::cout << " _PRIVATE_"; break; default: break; } std::cout << std::endl; PrintVisitor visitor; Loading tools/aapt2/JavaClassGenerator.cpp +34 −5 Original line number Diff line number Diff line Loading @@ -77,6 +77,18 @@ static std::u16string transform(const StringPiece16& symbol) { return output; } bool JavaClassGenerator::skipSymbol(SymbolState state) { switch (mOptions.types) { case JavaClassGeneratorOptions::SymbolTypes::kAll: return false; case JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate: return state == SymbolState::kUndefined; case JavaClassGeneratorOptions::SymbolTypes::kPublic: return state != SymbolState::kPublic; } return true; } void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGenerate, const std::u16string& entryName, const Styleable* styleable, Loading Loading @@ -121,7 +133,7 @@ void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGen // We may reference IDs from other packages, so prefix the entry name with // the package. const ResourceNameRef& itemName = sortedAttributes[i].second; if (packageNameToGenerate != itemName.package) { if (!itemName.package.empty() && packageNameToGenerate != itemName.package) { *out << "_" << transform(itemName.package); } *out << "_" << transform(itemName.entry) << " = " << i << ";\n"; Loading @@ -137,7 +149,11 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate std::u16string unmangledPackage; std::u16string unmangledName; for (const auto& entry : type->entries) { ResourceId id = { package->id.value(), type->id.value(), entry->id.value() }; if (skipSymbol(entry->symbolStatus.state)) { continue; } ResourceId id(package->id.value(), type->id.value(), entry->id.value()); assert(id.isValid()); unmangledName = entry->name; Loading @@ -157,7 +173,7 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate } if (!isValidSymbol(unmangledName)) { ResourceNameRef resourceName = { packageNameToGenerate, type->type, unmangledName }; ResourceNameRef resourceName(packageNameToGenerate, type->type, unmangledName); std::stringstream err; err << "invalid symbol name '" << resourceName << "'"; mError = err.str(); Loading @@ -177,13 +193,24 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate } bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, std::ostream* out) { generateHeader(packageNameToGenerate, out); return generate(packageNameToGenerate, packageNameToGenerate, out); } bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, const StringPiece16& outPackageName, std::ostream* out) { generateHeader(outPackageName, out); *out << "public final class R {\n"; for (const auto& package : mTable->packages) { for (const auto& type : package->types) { *out << " public static final class " << type->type << " {\n"; StringPiece16 typeStr; if (type->type == ResourceType::kAttrPrivate) { typeStr = toString(ResourceType::kAttr); } else { typeStr = toString(type->type); } *out << " public static final class " << typeStr << " {\n"; if (!generateType(packageNameToGenerate, package.get(), type.get(), out)) { return false; } Loading @@ -196,4 +223,6 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, st return true; } } // namespace aapt tools/aapt2/JavaClassGenerator.h +18 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,17 @@ struct JavaClassGeneratorOptions { * on resource entries. Default is true. */ bool useFinal = true; enum class SymbolTypes { kAll, kPublicPrivate, kPublic, }; /* * */ SymbolTypes types = SymbolTypes::kAll; }; /* Loading @@ -49,7 +60,11 @@ public: * We need to generate these symbols in a separate file. * Returns true on success. */ bool generate(const StringPiece16& package, std::ostream* out); bool generate(const StringPiece16& packageNameToGenerate, std::ostream* out); bool generate(const StringPiece16& packageNameToGenerate, const StringPiece16& outputPackageName, std::ostream* out); const std::string& getError() const; Loading @@ -64,6 +79,8 @@ private: const Styleable* styleable, std::ostream* out); bool skipSymbol(SymbolState state); ResourceTable* mTable; JavaClassGeneratorOptions mOptions; std::string mError; Loading tools/aapt2/JavaClassGenerator_test.cpp +81 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,87 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { output.find("public static final int hey_dude_cool_attr = 0;")); } TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .setPackageId(u"android", 0x01) .addSimple(u"@android:id/one", ResourceId(0x01020000)) .addSimple(u"@android:id/com.foo$two", ResourceId(0x01020001)) .build(); JavaClassGenerator generator(table.get(), {}); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", u"com.android.internal", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("package com.android.internal;")); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("com_foo$two")); } TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .setPackageId(u"android", 0x01) .addSimple(u"@android:^attr-private/one", ResourceId(0x01010000)) .build(); JavaClassGenerator generator(table.get(), {}); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final class attr")); EXPECT_EQ(std::string::npos, output.find("public static final class ^attr-private")); } TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { StdErrDiagnostics diag; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .setPackageId(u"android", 0x01) .addSimple(u"@android:id/one", ResourceId(0x01020000)) .addSimple(u"@android:id/two", ResourceId(0x01020001)) .addSimple(u"@android:id/three", ResourceId(0x01020002)) .build(); ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/one"), {}, {}, SymbolState::kPublic, &diag)); ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/two"), {}, {}, SymbolState::kPrivate, &diag)); JavaClassGeneratorOptions options; options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic; { JavaClassGenerator generator(table.get(), options); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("three")); } options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate; { JavaClassGenerator generator(table.get(), options); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two = 0x01020001;")); EXPECT_EQ(std::string::npos, output.find("three")); } options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; { JavaClassGenerator generator(table.get(), options); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two = 0x01020001;")); EXPECT_NE(std::string::npos, output.find("public static final int three = 0x01020002;")); } } /* * TODO(adamlesinski): Re-enable this once we get merging working again. * TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) { Loading tools/aapt2/ResourceParser.cpp +32 −5 Original line number Diff line number Diff line Loading @@ -18,10 +18,11 @@ #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" #include "util/Util.h" #include "ValueVisitor.h" #include "XmlPullParser.h" #include "util/Util.h" #include <sstream> namespace aapt { Loading Loading @@ -184,7 +185,7 @@ struct ParsedResource { ResourceName name; Source source; ResourceId id; bool markPublic = false; SymbolState symbolState = SymbolState::kUndefined; std::unique_ptr<Value> value; std::list<ParsedResource> childResources; }; Loading @@ -192,9 +193,11 @@ struct ParsedResource { // Recursively adds resources to the ResourceTable. static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config, IDiagnostics* diag, ParsedResource* res) { if (res->markPublic && !table->markPublic(res->name, res->id, res->source, diag)) { if (res->symbolState != SymbolState::kUndefined) { if (!table->setSymbolState(res->name, res->id, res->source, res->symbolState, diag)) { return false; } } if (!res->value) { return true; Loading Loading @@ -318,6 +321,8 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { result = parseAttr(parser, &parsedResource); } else if (elementName == u"public") { result = parsePublic(parser, &parsedResource); } else if (elementName == u"java-symbol" || elementName == u"symbol") { result = parseSymbol(parser, &parsedResource); } else { mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber())) << "unknown resource type '" << elementName << "'"); Loading Loading @@ -506,7 +511,29 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResou outResource->value = util::make_unique<Id>(); } outResource->markPublic = true; outResource->symbolState = SymbolState::kPublic; return true; } bool ResourceParser::parseSymbol(XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); Maybe<StringPiece16> maybeType = findNonEmptyAttribute(parser, u"type"); if (!maybeType) { mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a " "'type' attribute"); return false; } const ResourceType* parsedType = parseResourceType(maybeType.value()); if (!parsedType) { mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value() << "' in <" << parser->getElementName() << ">"); return false; } outResource->name.type = *parsedType; outResource->symbolState = SymbolState::kPrivate; return true; } Loading Loading
tools/aapt2/Debug.cpp +9 −8 Original line number Diff line number Diff line Loading @@ -124,17 +124,18 @@ void Debug::printTable(ResourceTable* table) { } for (const ResourceEntry* entry : sortedEntries) { ResourceId id = { package->id ? package->id.value() : uint8_t(0), ResourceId id(package->id ? package->id.value() : uint8_t(0), type->id ? type->id.value() : uint8_t(0), entry->id ? entry->id.value() : uint16_t(0) }; entry->id ? entry->id.value() : uint16_t(0)); ResourceName name(package->name, type->type, entry->name); ResourceName name = { package->name, type->type, entry->name }; std::cout << " spec resource " << id << " " << name; if (entry->publicStatus.isPublic) { std::cout << " PUBLIC"; switch (entry->symbolStatus.state) { case SymbolState::kPublic: std::cout << " PUBLIC"; break; case SymbolState::kPrivate: std::cout << " _PRIVATE_"; break; default: break; } std::cout << std::endl; PrintVisitor visitor; Loading
tools/aapt2/JavaClassGenerator.cpp +34 −5 Original line number Diff line number Diff line Loading @@ -77,6 +77,18 @@ static std::u16string transform(const StringPiece16& symbol) { return output; } bool JavaClassGenerator::skipSymbol(SymbolState state) { switch (mOptions.types) { case JavaClassGeneratorOptions::SymbolTypes::kAll: return false; case JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate: return state == SymbolState::kUndefined; case JavaClassGeneratorOptions::SymbolTypes::kPublic: return state != SymbolState::kPublic; } return true; } void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGenerate, const std::u16string& entryName, const Styleable* styleable, Loading Loading @@ -121,7 +133,7 @@ void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGen // We may reference IDs from other packages, so prefix the entry name with // the package. const ResourceNameRef& itemName = sortedAttributes[i].second; if (packageNameToGenerate != itemName.package) { if (!itemName.package.empty() && packageNameToGenerate != itemName.package) { *out << "_" << transform(itemName.package); } *out << "_" << transform(itemName.entry) << " = " << i << ";\n"; Loading @@ -137,7 +149,11 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate std::u16string unmangledPackage; std::u16string unmangledName; for (const auto& entry : type->entries) { ResourceId id = { package->id.value(), type->id.value(), entry->id.value() }; if (skipSymbol(entry->symbolStatus.state)) { continue; } ResourceId id(package->id.value(), type->id.value(), entry->id.value()); assert(id.isValid()); unmangledName = entry->name; Loading @@ -157,7 +173,7 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate } if (!isValidSymbol(unmangledName)) { ResourceNameRef resourceName = { packageNameToGenerate, type->type, unmangledName }; ResourceNameRef resourceName(packageNameToGenerate, type->type, unmangledName); std::stringstream err; err << "invalid symbol name '" << resourceName << "'"; mError = err.str(); Loading @@ -177,13 +193,24 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate } bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, std::ostream* out) { generateHeader(packageNameToGenerate, out); return generate(packageNameToGenerate, packageNameToGenerate, out); } bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, const StringPiece16& outPackageName, std::ostream* out) { generateHeader(outPackageName, out); *out << "public final class R {\n"; for (const auto& package : mTable->packages) { for (const auto& type : package->types) { *out << " public static final class " << type->type << " {\n"; StringPiece16 typeStr; if (type->type == ResourceType::kAttrPrivate) { typeStr = toString(ResourceType::kAttr); } else { typeStr = toString(type->type); } *out << " public static final class " << typeStr << " {\n"; if (!generateType(packageNameToGenerate, package.get(), type.get(), out)) { return false; } Loading @@ -196,4 +223,6 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, st return true; } } // namespace aapt
tools/aapt2/JavaClassGenerator.h +18 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,17 @@ struct JavaClassGeneratorOptions { * on resource entries. Default is true. */ bool useFinal = true; enum class SymbolTypes { kAll, kPublicPrivate, kPublic, }; /* * */ SymbolTypes types = SymbolTypes::kAll; }; /* Loading @@ -49,7 +60,11 @@ public: * We need to generate these symbols in a separate file. * Returns true on success. */ bool generate(const StringPiece16& package, std::ostream* out); bool generate(const StringPiece16& packageNameToGenerate, std::ostream* out); bool generate(const StringPiece16& packageNameToGenerate, const StringPiece16& outputPackageName, std::ostream* out); const std::string& getError() const; Loading @@ -64,6 +79,8 @@ private: const Styleable* styleable, std::ostream* out); bool skipSymbol(SymbolState state); ResourceTable* mTable; JavaClassGeneratorOptions mOptions; std::string mError; Loading
tools/aapt2/JavaClassGenerator_test.cpp +81 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,87 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { output.find("public static final int hey_dude_cool_attr = 0;")); } TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .setPackageId(u"android", 0x01) .addSimple(u"@android:id/one", ResourceId(0x01020000)) .addSimple(u"@android:id/com.foo$two", ResourceId(0x01020001)) .build(); JavaClassGenerator generator(table.get(), {}); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", u"com.android.internal", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("package com.android.internal;")); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("com_foo$two")); } TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .setPackageId(u"android", 0x01) .addSimple(u"@android:^attr-private/one", ResourceId(0x01010000)) .build(); JavaClassGenerator generator(table.get(), {}); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final class attr")); EXPECT_EQ(std::string::npos, output.find("public static final class ^attr-private")); } TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { StdErrDiagnostics diag; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .setPackageId(u"android", 0x01) .addSimple(u"@android:id/one", ResourceId(0x01020000)) .addSimple(u"@android:id/two", ResourceId(0x01020001)) .addSimple(u"@android:id/three", ResourceId(0x01020002)) .build(); ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/one"), {}, {}, SymbolState::kPublic, &diag)); ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/two"), {}, {}, SymbolState::kPrivate, &diag)); JavaClassGeneratorOptions options; options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic; { JavaClassGenerator generator(table.get(), options); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("three")); } options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate; { JavaClassGenerator generator(table.get(), options); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two = 0x01020001;")); EXPECT_EQ(std::string::npos, output.find("three")); } options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; { JavaClassGenerator generator(table.get(), options); std::stringstream out; ASSERT_TRUE(generator.generate(u"android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two = 0x01020001;")); EXPECT_NE(std::string::npos, output.find("public static final int three = 0x01020002;")); } } /* * TODO(adamlesinski): Re-enable this once we get merging working again. * TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) { Loading
tools/aapt2/ResourceParser.cpp +32 −5 Original line number Diff line number Diff line Loading @@ -18,10 +18,11 @@ #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" #include "util/Util.h" #include "ValueVisitor.h" #include "XmlPullParser.h" #include "util/Util.h" #include <sstream> namespace aapt { Loading Loading @@ -184,7 +185,7 @@ struct ParsedResource { ResourceName name; Source source; ResourceId id; bool markPublic = false; SymbolState symbolState = SymbolState::kUndefined; std::unique_ptr<Value> value; std::list<ParsedResource> childResources; }; Loading @@ -192,9 +193,11 @@ struct ParsedResource { // Recursively adds resources to the ResourceTable. static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config, IDiagnostics* diag, ParsedResource* res) { if (res->markPublic && !table->markPublic(res->name, res->id, res->source, diag)) { if (res->symbolState != SymbolState::kUndefined) { if (!table->setSymbolState(res->name, res->id, res->source, res->symbolState, diag)) { return false; } } if (!res->value) { return true; Loading Loading @@ -318,6 +321,8 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { result = parseAttr(parser, &parsedResource); } else if (elementName == u"public") { result = parsePublic(parser, &parsedResource); } else if (elementName == u"java-symbol" || elementName == u"symbol") { result = parseSymbol(parser, &parsedResource); } else { mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber())) << "unknown resource type '" << elementName << "'"); Loading Loading @@ -506,7 +511,29 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResou outResource->value = util::make_unique<Id>(); } outResource->markPublic = true; outResource->symbolState = SymbolState::kPublic; return true; } bool ResourceParser::parseSymbol(XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); Maybe<StringPiece16> maybeType = findNonEmptyAttribute(parser, u"type"); if (!maybeType) { mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a " "'type' attribute"); return false; } const ResourceType* parsedType = parseResourceType(maybeType.value()); if (!parsedType) { mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value() << "' in <" << parser->getElementName() << ">"); return false; } outResource->name.type = *parsedType; outResource->symbolState = SymbolState::kPrivate; return true; } Loading