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