From e78fd617ec60139a973a01925fa7adad31febb39 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Thu, 22 Oct 2015 12:48:43 -0700 Subject: [PATCH] AAPT2: Move comments and source into Value Values are closely related to where they were defined, so this information should live inside the Value. This also enables comments to be attached to nested Values. Change-Id: Ic7481b5a5f26d0ef248d638e2e29252f88154581 --- tools/aapt2/JavaClassGenerator_test.cpp | 6 +- tools/aapt2/ResourceParser.cpp | 30 ++++-- tools/aapt2/ResourceParser.h | 11 ++- tools/aapt2/ResourceParser_test.cpp | 37 +++++-- tools/aapt2/ResourceTable.cpp | 97 +++++++++---------- tools/aapt2/ResourceTable.h | 37 +++---- tools/aapt2/ResourceTable_test.cpp | 50 ++++++---- tools/aapt2/ResourceValues.cpp | 13 +-- tools/aapt2/ResourceValues.h | 44 +++++++-- tools/aapt2/ValueVisitor.h | 12 +++ tools/aapt2/XmlPullParser.cpp | 2 +- tools/aapt2/XmlPullParser.h | 1 - tools/aapt2/flatten/TableFlattener.cpp | 38 +++++--- tools/aapt2/link/AutoVersioner.cpp | 32 +++--- tools/aapt2/link/Link.cpp | 22 +++-- .../aapt2/link/PrivateAttributeMover_test.cpp | 8 +- tools/aapt2/link/ReferenceLinker.cpp | 4 +- tools/aapt2/link/TableMerger.cpp | 34 +++---- tools/aapt2/process/SymbolTable.cpp | 24 ++--- tools/aapt2/test/Builders.h | 56 +++++++++-- .../aapt2/unflatten/BinaryResourceParser.cpp | 23 ++--- tools/aapt2/unflatten/BinaryResourceParser.h | 24 +++-- tools/aapt2/util/Comparators.h | 30 ++++++ 23 files changed, 386 insertions(+), 249 deletions(-) create mode 100644 tools/aapt2/util/Comparators.h diff --git a/tools/aapt2/JavaClassGenerator_test.cpp b/tools/aapt2/JavaClassGenerator_test.cpp index becf99b521ed4..cc5e98150ae3f 100644 --- a/tools/aapt2/JavaClassGenerator_test.cpp +++ b/tools/aapt2/JavaClassGenerator_test.cpp @@ -105,11 +105,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { .addSimple(u"@android:id/one", ResourceId(0x01020000)) .addSimple(u"@android:id/two", ResourceId(0x01020001)) .addSimple(u"@android:id/three", ResourceId(0x01020002)) + .setSymbolState(u"@android:id/one", ResourceId(0x01020000), SymbolState::kPublic) + .setSymbolState(u"@android:id/two", ResourceId(0x01020001), SymbolState::kPrivate) .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; diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index bfef9d06d7424..44710ebc9dc44 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -186,6 +186,7 @@ struct ParsedResource { Source source; ResourceId id; SymbolState symbolState = SymbolState::kUndefined; + std::u16string comment; std::unique_ptr value; std::list childResources; }; @@ -194,7 +195,11 @@ struct ParsedResource { static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config, IDiagnostics* diag, ParsedResource* res) { if (res->symbolState != SymbolState::kUndefined) { - if (!table->setSymbolState(res->name, res->id, res->source, res->symbolState, diag)) { + Symbol symbol; + symbol.state = res->symbolState; + symbol.source = res->source; + symbol.comment = res->comment; + if (!table->setSymbolState(res->name, res->id, symbol, diag)) { return false; } } @@ -203,7 +208,11 @@ static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& c return true; } - if (!table->addResource(res->name, res->id, config, res->source, std::move(res->value), diag)) { + // Attach the comment, source and config to the value. + res->value->setComment(std::move(res->comment)); + res->value->setSource(std::move(res->source)); + + if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) { return false; } @@ -275,6 +284,7 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { ParsedResource parsedResource; parsedResource.name.entry = maybeName.value().toString(); parsedResource.source = mSource.withLine(parser->getLineNumber()); + parsedResource.comment = std::move(comment); bool result = true; if (elementName == u"id") { @@ -368,8 +378,8 @@ enum { * an Item. If allowRawValue is false, nullptr is returned in this * case. */ -std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, uint32_t typeMask, - bool allowRawValue) { +std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, const uint32_t typeMask, + const bool allowRawValue) { const size_t beginXmlLine = parser->getLineNumber(); std::u16string rawValue; @@ -386,8 +396,9 @@ std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, uint32_t t auto onCreateReference = [&](const ResourceName& name) { // name.package can be empty here, as it will assume the package name of the table. - mTable->addResource(name, {}, mSource.withLine(beginXmlLine), util::make_unique(), - mDiag); + std::unique_ptr id = util::make_unique(); + id->setSource(mSource.withLine(beginXmlLine)); + mTable->addResource(name, {}, std::move(id), mDiag); }; // Process the raw value. @@ -411,11 +422,12 @@ std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, uint32_t t mTable->stringPool.makeRef(styleString.str, StringPool::Context{ 1, mConfig })); } - // We can't parse this so return a RawString if we are allowed. if (allowRawValue) { + // We can't parse this so return a RawString if we are allowed. return util::make_unique( mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig })); } + return {}; } @@ -683,8 +695,8 @@ Maybe ResourceParser::parseEnumOrFlagItem(XmlPullParser* pars } return Attribute::Symbol{ - Reference(ResourceName{ {}, ResourceType::kId, maybeName.value().toString() }), - val.data }; + Reference(ResourceName({}, ResourceType::kId, maybeName.value().toString())), + val.data }; } static Maybe parseXmlAttributeName(StringPiece16 str) { diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 34c68d7257a35..2d5a29df2c491 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -65,12 +65,13 @@ private: StyleString* outStyleString); /* - * Parses the XML subtree and converts it to an Item. The type of Item that can be - * parsed is denoted by the `typeMask`. If `allowRawValue` is true and the subtree - * can not be parsed as a regular Item, then a RawString is returned. Otherwise - * this returns nullptr. + * Parses the XML subtree and returns an Item. + * The type of Item that can be parsed is denoted by the `typeMask`. + * If `allowRawValue` is true and the subtree can not be parsed as a regular Item, then a + * RawString is returned. Otherwise this returns false; */ - std::unique_ptr parseXml(XmlPullParser* parser, uint32_t typeMask, bool allowRawValue); + std::unique_ptr parseXml(XmlPullParser* parser, const uint32_t typeMask, + const bool allowRawValue); bool parseResources(XmlPullParser* parser); bool parseString(XmlPullParser* parser, ParsedResource* outResource); diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index a7e9d390ef4af..af6bf67c4a3b0 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -379,18 +379,39 @@ TEST_F(ResourceParserTest, ParsePlural) { } TEST_F(ResourceParserTest, ParseCommentsWithResource) { - std::string input = "\n" + std::string input = "\n" "Hi"; ASSERT_TRUE(testParse(input)); - Maybe result = mTable.findResource( - test::parseNameOrDie(u"@string/foo")); - AAPT_ASSERT_TRUE(result); + String* value = test::getValue(&mTable, u"@string/foo"); + ASSERT_NE(nullptr, value); + EXPECT_EQ(value->getComment(), u"This is a comment"); +} - ResourceEntry* entry = result.value().entry; - ASSERT_NE(entry, nullptr); - ASSERT_FALSE(entry->values.empty()); - EXPECT_EQ(entry->values.front().comment, u"This is a comment"); +TEST_F(ResourceParserTest, DoNotCombineMultipleComments) { + std::string input = "\n" + "\n" + "Hi"; + + ASSERT_TRUE(testParse(input)); + + String* value = test::getValue(&mTable, u"@string/foo"); + ASSERT_NE(nullptr, value); + EXPECT_EQ(value->getComment(), u"Two"); +} + +TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) { + std::string input = "\n" + "\n" + " Hi\n" + "\n" + ""; + + ASSERT_TRUE(testParse(input)); + + String* value = test::getValue(&mTable, u"@string/foo"); + ASSERT_NE(nullptr, value); + EXPECT_EQ(value->getComment(), u"One"); } /* diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index 84674e841063d..fa4b1094434b7 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -19,6 +19,8 @@ #include "ResourceTable.h" #include "ResourceValues.h" #include "ValueVisitor.h" + +#include "util/Comparators.h" #include "util/Util.h" #include @@ -29,10 +31,6 @@ namespace aapt { -static bool compareConfigs(const ResourceConfigValue& lhs, const ConfigDescription& rhs) { - return lhs.config < rhs; -} - static bool lessThanType(const std::unique_ptr& lhs, ResourceType rhs) { return lhs->type < rhs; } @@ -191,52 +189,50 @@ static constexpr const char16_t* kValidNameChars = u"._-"; static constexpr const char16_t* kValidNameMangledChars = u"._-$"; bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config, - const Source& source, std::unique_ptr value, - IDiagnostics* diag) { - return addResourceImpl(name, ResourceId{}, config, source, std::move(value), kValidNameChars, - diag); + std::unique_ptr value, IDiagnostics* diag) { + return addResourceImpl(name, {}, config, std::move(value), kValidNameChars, diag); } bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId, - const ConfigDescription& config, const Source& source, - std::unique_ptr value, IDiagnostics* diag) { - return addResourceImpl(name, resId, config, source, std::move(value), kValidNameChars, diag); + const ConfigDescription& config, std::unique_ptr value, + IDiagnostics* diag) { + return addResourceImpl(name, resId, config, std::move(value), kValidNameChars, diag); } bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config, const Source& source, const StringPiece16& path, IDiagnostics* diag) { - return addResourceImpl(name, ResourceId{}, config, source, - util::make_unique(stringPool.makeRef(path)), - kValidNameChars, diag); + std::unique_ptr fileRef = util::make_unique( + stringPool.makeRef(path)); + fileRef->setSource(source); + return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars, diag); } bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config, - const Source& source, std::unique_ptr value, IDiagnostics* diag) { - return addResourceImpl(name, ResourceId{}, config, source, std::move(value), - kValidNameMangledChars, diag); + return addResourceImpl(name, ResourceId{}, config, std::move(value), kValidNameMangledChars, + diag); } bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name, const ResourceId id, const ConfigDescription& config, - const Source& source, std::unique_ptr value, IDiagnostics* diag) { - return addResourceImpl(name, id, config, source, std::move(value), - kValidNameMangledChars, diag); + return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars, diag); } bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId resId, - const ConfigDescription& config, const Source& source, - std::unique_ptr value, const char16_t* validChars, - IDiagnostics* diag) { + const ConfigDescription& config, std::unique_ptr value, + const char16_t* validChars, IDiagnostics* diag) { + assert(value && "value can't be nullptr"); + assert(diag && "diagnostics can't be nullptr"); + auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars); if (badCharIter != name.entry.end()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(value->getSource()) << "resource '" << name << "' has invalid entry name '" @@ -249,7 +245,7 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceI ResourceTablePackage* package = findOrCreatePackage(name.package); if (resId.isValid() && package->id && package->id.value() != resId.packageId()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(value->getSource()) << "trying to add resource '" << name << "' with ID " @@ -263,7 +259,7 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceI ResourceTableType* type = package->findOrCreateType(name.type); if (resId.isValid() && type->id && type->id.value() != resId.typeId()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(value->getSource()) << "trying to add resource '" << name << "' with ID " @@ -277,7 +273,7 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceI ResourceEntry* entry = type->findOrCreateEntry(name.entry); if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(value->getSource()) << "trying to add resource '" << name << "' with ID " @@ -288,20 +284,20 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceI } const auto endIter = entry->values.end(); - auto iter = std::lower_bound(entry->values.begin(), endIter, config, compareConfigs); + auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmp::lessThan); if (iter == endIter || iter->config != config) { // This resource did not exist before, add it. - entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) }); + entry->values.insert(iter, ResourceConfigValue{ config, std::move(value) }); } else { int collisionResult = resolveValueCollision(iter->value.get(), value.get()); if (collisionResult > 0) { // Take the incoming value. - *iter = ResourceConfigValue{ config, source, {}, std::move(value) }; + iter->value = std::move(value); } else if (collisionResult == 0) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(value->getSource()) << "duplicate value for resource '" << name << "' " - << "with config '" << iter->config << "'"); - diag->error(DiagMessage(iter->source) + << "with config '" << config << "'"); + diag->error(DiagMessage(iter->value->getSource()) << "resource previously defined here"); return false; } @@ -316,27 +312,29 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceI } bool ResourceTable::setSymbolState(const ResourceNameRef& name, const ResourceId resId, - const Source& source, SymbolState state, IDiagnostics* diag) { - return setSymbolStateImpl(name, resId, source, state, kValidNameChars, diag); + const Symbol& symbol, IDiagnostics* diag) { + return setSymbolStateImpl(name, resId, symbol, kValidNameChars, diag); } -bool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId, - const Source& source, SymbolState state, - IDiagnostics* diag) { - return setSymbolStateImpl(name, resId, source, state, kValidNameMangledChars, diag); +bool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name, + const ResourceId resId, + const Symbol& symbol, IDiagnostics* diag) { + return setSymbolStateImpl(name, resId, symbol, kValidNameMangledChars, diag); } bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId, - const Source& source, SymbolState state, - const char16_t* validChars, IDiagnostics* diag) { - if (state == SymbolState::kUndefined) { + const Symbol& symbol, const char16_t* validChars, + IDiagnostics* diag) { + assert(diag && "diagnostics can't be nullptr"); + + if (symbol.state == SymbolState::kUndefined) { // Nothing to do. return true; } auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars); if (badCharIter != name.entry.end()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(symbol.source) << "resource '" << name << "' has invalid entry name '" @@ -349,7 +347,7 @@ bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const Resour ResourceTablePackage* package = findOrCreatePackage(name.package); if (resId.isValid() && package->id && package->id.value() != resId.packageId()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(symbol.source) << "trying to add resource '" << name << "' with ID " @@ -363,7 +361,7 @@ bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const Resour ResourceTableType* type = package->findOrCreateType(name.type); if (resId.isValid() && type->id && type->id.value() != resId.typeId()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(symbol.source) << "trying to add resource '" << name << "' with ID " @@ -377,7 +375,7 @@ bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const Resour ResourceEntry* entry = type->findOrCreateEntry(name.entry); if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) { - diag->error(DiagMessage(source) + diag->error(DiagMessage(symbol.source) << "trying to add resource '" << name << "' with ID " @@ -388,15 +386,14 @@ bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const Resour } // Only mark the type state as public, it doesn't care about being private. - if (state == SymbolState::kPublic) { + if (symbol.state == SymbolState::kPublic) { type->symbolStatus.state = SymbolState::kPublic; } // Downgrading to a private symbol from a public one is not allowed. if (entry->symbolStatus.state != SymbolState::kPublic) { - if (entry->symbolStatus.state != state) { - entry->symbolStatus.state = state; - entry->symbolStatus.source = source; + if (entry->symbolStatus.state != symbol.state) { + entry->symbolStatus = std::move(symbol); } } diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index be909361bef10..980504be377b2 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -47,12 +47,10 @@ struct Symbol { }; /** - * The resource value for a specific configuration. + * Represents a value defined for a given configuration. */ struct ResourceConfigValue { ConfigDescription config; - Source source; - std::u16string comment; std::unique_ptr value; }; @@ -158,12 +156,11 @@ public: static int resolveValueCollision(Value* existing, Value* incoming); bool addResource(const ResourceNameRef& name, const ConfigDescription& config, - const Source& source, std::unique_ptr value, - IDiagnostics* diag); + std::unique_ptr value, IDiagnostics* diag); bool addResource(const ResourceNameRef& name, const ResourceId resId, - const ConfigDescription& config, const Source& source, - std::unique_ptr value, IDiagnostics* diag); + const ConfigDescription& config, std::unique_ptr value, + IDiagnostics* diag); bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config, const Source& source, const StringPiece16& path, IDiagnostics* diag); @@ -174,18 +171,18 @@ public: * names. */ bool addResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config, - const Source& source, std::unique_ptr value, - IDiagnostics* diag); + std::unique_ptr value, IDiagnostics* diag); bool addResourceAllowMangled(const ResourceNameRef& name, const ResourceId id, - const ConfigDescription& config, - const Source& source, std::unique_ptr value, + const ConfigDescription& config, std::unique_ptr value, IDiagnostics* diag); - bool setSymbolState(const ResourceNameRef& name, const ResourceId resId, const Source& source, - SymbolState state, IDiagnostics* diag); + bool setSymbolState(const ResourceNameRef& name, const ResourceId resId, + const Symbol& symbol, IDiagnostics* diag); + bool setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId, - const Source& source, SymbolState state, IDiagnostics* diag); + const Symbol& symbol, IDiagnostics* diag); + struct SearchResult { ResourceTablePackage* package; ResourceTableType* type; @@ -224,13 +221,11 @@ public: private: ResourceTablePackage* findOrCreatePackage(const StringPiece16& name); - bool addResourceImpl(const ResourceNameRef& name, const ResourceId resId, - const ConfigDescription& config, const Source& source, - std::unique_ptr value, const char16_t* validChars, - IDiagnostics* diag); - bool setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId, - const Source& source, SymbolState state, const char16_t* validChars, - IDiagnostics* diag); + bool addResourceImpl(const ResourceNameRef& name, ResourceId resId, + const ConfigDescription& config, std::unique_ptr value, + const char16_t* validChars, IDiagnostics* diag); + bool setSymbolStateImpl(const ResourceNameRef& name, ResourceId resId, + const Symbol& symbol, const char16_t* validChars, IDiagnostics* diag); }; } // namespace aapt diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp index 2055a80aaba6c..42508fe154b8d 100644 --- a/tools/aapt2/ResourceTable_test.cpp +++ b/tools/aapt2/ResourceTable_test.cpp @@ -19,7 +19,7 @@ #include "ResourceValues.h" #include "util/Util.h" -#include "test/Common.h" +#include "test/Builders.h" #include #include @@ -42,22 +42,26 @@ TEST_F(ResourceTableTest, FailToAddResourceWithBadName) { ResourceTable table; EXPECT_FALSE(table.addResource( - ResourceNameRef{ u"android", ResourceType::kId, u"hey,there" }, - {}, Source{ "test.xml", 21 }, - util::make_unique(), &mDiagnostics)); + ResourceNameRef(u"android", ResourceType::kId, u"hey,there"), + ConfigDescription{}, + test::ValueBuilder().setSource("test.xml", 21u).build(), + &mDiagnostics)); EXPECT_FALSE(table.addResource( - ResourceNameRef{ u"android", ResourceType::kId, u"hey:there" }, - {}, Source{ "test.xml", 21 }, - util::make_unique(), &mDiagnostics)); + ResourceNameRef(u"android", ResourceType::kId, u"hey:there"), + ConfigDescription{}, + test::ValueBuilder().setSource("test.xml", 21u).build(), + &mDiagnostics)); } TEST_F(ResourceTableTest, AddOneResource) { ResourceTable table; - EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"), {}, - Source{ "test/path/file.xml", 23 }, - util::make_unique(), &mDiagnostics)); + EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"), + ConfigDescription{}, + test::ValueBuilder() + .setSource("test/path/file.xml", 23u).build(), + &mDiagnostics)); ASSERT_NE(nullptr, test::getValue(&table, u"@android:attr/id")); } @@ -71,23 +75,29 @@ TEST_F(ResourceTableTest, AddMultipleResources) { EXPECT_TRUE(table.addResource( test::parseNameOrDie(u"@android:attr/layout_width"), - config, Source{ "test/path/file.xml", 10 }, - util::make_unique(), &mDiagnostics)); + config, + test::ValueBuilder().setSource("test/path/file.xml", 10u).build(), + &mDiagnostics)); EXPECT_TRUE(table.addResource( test::parseNameOrDie(u"@android:attr/id"), - config, Source{ "test/path/file.xml", 12 }, - util::make_unique(), &mDiagnostics)); + config, + test::ValueBuilder().setSource("test/path/file.xml", 12u).build(), + &mDiagnostics)); EXPECT_TRUE(table.addResource( test::parseNameOrDie(u"@android:string/ok"), - config, Source{ "test/path/file.xml", 14 }, - util::make_unique(), &mDiagnostics)); + config, + test::ValueBuilder().setSource("test/path/file.xml", 14u).build(), + &mDiagnostics)); EXPECT_TRUE(table.addResource( test::parseNameOrDie(u"@android:string/ok"), - languageConfig, Source{ "test/path/file.xml", 20 }, - util::make_unique(android::Res_value{}), &mDiagnostics)); + languageConfig, + test::ValueBuilder(android::Res_value{}) + .setSource("test/path/file.xml", 20u) + .build(), + &mDiagnostics)); ASSERT_NE(nullptr, test::getValue(&table, u"@android:attr/layout_width")); ASSERT_NE(nullptr, test::getValue(&table, u"@android:attr/id")); @@ -99,14 +109,14 @@ TEST_F(ResourceTableTest, AddMultipleResources) { TEST_F(ResourceTableTest, OverrideWeakResourceValue) { ResourceTable table; - ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), {}, {}, + ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{}, util::make_unique(true), &mDiagnostics)); Attribute* attr = test::getValue(&table, u"@android:attr/foo"); ASSERT_NE(nullptr, attr); EXPECT_TRUE(attr->isWeak()); - ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), {}, {}, + ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{}, util::make_unique(false), &mDiagnostics)); attr = test::getValue(&table, u"@android:attr/foo"); diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index ecc5cd2bdcfab..f312d75ab1e9b 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -15,11 +15,12 @@ */ #include "Resource.h" -#include "flatten/ResourceTypeExtensions.h" #include "ResourceValues.h" -#include "util/Util.h" #include "ValueVisitor.h" +#include "util/Util.h" +#include "flatten/ResourceTypeExtensions.h" + #include #include @@ -35,18 +36,10 @@ void BaseItem::accept(RawValueVisitor* visitor) { visitor->visit(static_cast(this)); } -bool Value::isItem() const { - return false; -} - bool Value::isWeak() const { return false; } -bool Item::isItem() const { - return true; -} - RawString::RawString(const StringPool::Ref& ref) : value(ref) { } diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h index 0dae091dffb43..26291536ae80f 100644 --- a/tools/aapt2/ResourceValues.h +++ b/tools/aapt2/ResourceValues.h @@ -40,17 +40,42 @@ struct RawValueVisitor; struct Value { virtual ~Value() = default; - /** - * Whether or not this is an Item. - */ - virtual bool isItem() const; - /** * Whether this value is weak and can be overridden without * warning or error. Default for base class is false. */ virtual bool isWeak() const; + /** + * Returns the source where this value was defined. + */ + const Source& getSource() const { + return mSource; + } + + void setSource(const Source& source) { + mSource = source; + } + + void setSource(Source&& source) { + mSource = std::move(source); + } + + /** + * Returns the comment that was associated with this resource. + */ + StringPiece16 getComment() const { + return mComment; + } + + void setComment(const StringPiece16& str) { + mComment = str.toString(); + } + + void setComment(std::u16string&& str) { + mComment = std::move(str); + } + /** * Calls the appropriate overload of ValueVisitor. */ @@ -65,6 +90,10 @@ struct Value { * Human readable printout of this value. */ virtual void print(std::ostream* out) const = 0; + +private: + Source mSource; + std::u16string mComment; }; /** @@ -79,11 +108,6 @@ struct BaseValue : public Value { * A resource item with a single value. This maps to android::ResTable_entry. */ struct Item : public Value { - /** - * An Item is, of course, an Item. - */ - virtual bool isItem() const override; - /** * Clone the Item. */ diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h index ee058aa1a37b6..94042e3c2618c 100644 --- a/tools/aapt2/ValueVisitor.h +++ b/tools/aapt2/ValueVisitor.h @@ -114,6 +114,18 @@ struct DynCastVisitor : public RawValueVisitor { } }; +/** + * Specialization that checks if the value is an Item. + */ +template <> +struct DynCastVisitor : public RawValueVisitor { + Item* value = nullptr; + + void visitItem(Item* item) override { + value = item; + } +}; + /** * Returns a valid pointer to T if the Value is of subtype T. * Otherwise, returns nullptr. diff --git a/tools/aapt2/XmlPullParser.cpp b/tools/aapt2/XmlPullParser.cpp index 1b9499d78efb9..cff935c10aaef 100644 --- a/tools/aapt2/XmlPullParser.cpp +++ b/tools/aapt2/XmlPullParser.cpp @@ -97,7 +97,7 @@ const std::string& XmlPullParser::getLastError() const { } const std::u16string& XmlPullParser::getComment() const { - return mEventQueue.front().comment; + return mEventQueue.front().data1; } size_t XmlPullParser::getLineNumber() const { diff --git a/tools/aapt2/XmlPullParser.h b/tools/aapt2/XmlPullParser.h index f7d7a03a4352b..a0ce21dd3218f 100644 --- a/tools/aapt2/XmlPullParser.h +++ b/tools/aapt2/XmlPullParser.h @@ -158,7 +158,6 @@ private: size_t depth; std::u16string data1; std::u16string data2; - std::u16string comment; std::vector attributes; }; diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp index 095552aa7f316..47fa2a63d5533 100644 --- a/tools/aapt2/flatten/TableFlattener.cpp +++ b/tools/aapt2/flatten/TableFlattener.cpp @@ -292,7 +292,7 @@ private: SymbolWriter* mSymbols; StringPool* mSourcePool; - template + template T* writeEntry(FlatEntry* entry, BigBuffer* buffer) { static_assert(std::is_same::value || std::is_same::value, @@ -308,7 +308,7 @@ private: outEntry->flags |= ResTable_entry::FLAG_WEAK; } - if (!entry->value->isItem()) { + if (!IsItem) { outEntry->flags |= ResTable_entry::FLAG_COMPLEX; } @@ -329,8 +329,8 @@ private: } bool flattenValue(FlatEntry* entry, BigBuffer* buffer) { - if (entry->value->isItem()) { - writeEntry(entry, buffer); + if (Item* item = valueCast(entry->value)) { + writeEntry(entry, buffer); if (Reference* ref = valueCast(entry->value)) { if (!ref->id) { assert(ref->name && "reference must have at least a name"); @@ -339,12 +339,12 @@ private: } } Res_value* outValue = buffer->nextBlock(); - bool result = static_cast(entry->value)->flatten(outValue); + bool result = item->flatten(outValue); assert(result && "flatten failed"); outValue->size = util::hostToDevice16(sizeof(*outValue)); } else { const size_t beforeEntry = buffer->size(); - ResTable_entry_ext* outEntry = writeEntry(entry, buffer); + ResTable_entry_ext* outEntry = writeEntry(entry, buffer); MapFlattenVisitor visitor(mSymbols, entry, buffer); entry->value->accept(&visitor); outEntry->count = util::hostToDevice32(visitor.mEntryCount); @@ -551,17 +551,27 @@ private: // configuration available. Here we reverse this to match the binary table. std::map> configToEntryListMap; for (ResourceEntry* entry : sortedEntries) { - const size_t keyIndex = mKeyPool.makeRef(entry->name).getIndex(); + const uint32_t keyIndex = (uint32_t) mKeyPool.makeRef(entry->name).getIndex(); // Group values by configuration. for (auto& configValue : entry->values) { - configToEntryListMap[configValue.config].push_back(FlatEntry{ - entry, configValue.value.get(), (uint32_t) keyIndex, - (uint32_t)(mSourcePool->makeRef(util::utf8ToUtf16( - configValue.source.path)).getIndex()), - (uint32_t)(configValue.source.line - ? configValue.source.line.value() : 0) - }); + Value* value = configValue.value.get(); + + const StringPool::Ref sourceRef = mSourcePool->makeRef( + util::utf8ToUtf16(value->getSource().path)); + + uint32_t lineNumber = 0; + if (value->getSource().line) { + lineNumber = value->getSource().line.value(); + } + + configToEntryListMap[configValue.config] + .push_back(FlatEntry{ + entry, + value, + keyIndex, + (uint32_t) sourceRef.getIndex(), + lineNumber }); } } diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp index 0ccafc2107d01..11fcc5d6274d9 100644 --- a/tools/aapt2/link/AutoVersioner.cpp +++ b/tools/aapt2/link/AutoVersioner.cpp @@ -20,21 +20,18 @@ #include "ValueVisitor.h" #include "link/Linkers.h" +#include "util/Comparators.h" #include #include namespace aapt { -static bool cmpConfigValue(const ResourceConfigValue& lhs, const ConfigDescription& config) { - return lhs.config < config; -} - bool shouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config, const int sdkVersionToGenerate) { assert(sdkVersionToGenerate > config.sdkVersion); const auto endIter = entry->values.end(); - auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmpConfigValue); + auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmp::lessThan); // The source config came from this list, so it should be here. assert(iter != entry->values.end()); @@ -107,21 +104,16 @@ bool AutoVersioner::consume(IAaptContext* context, ResourceTable* table) { // We found attributes from a higher SDK level. Check that // there is no other defined resource for the version we want to // generate. - if (shouldGenerateVersionedResource(entry.get(), configValue.config, + if (shouldGenerateVersionedResource(entry.get(), + configValue.config, minSdkStripped.value())) { // Let's create a new Style for this versioned resource. ConfigDescription newConfig(configValue.config); newConfig.sdkVersion = minSdkStripped.value(); - ResourceConfigValue newValue = { - newConfig, - configValue.source, - configValue.comment, - std::unique_ptr(configValue.value->clone( - &table->stringPool)) - }; - - Style* newStyle = static_cast(newValue.value.get()); + std::unique_ptr