From dfbac39d3854daabdef722fd62ccb58203ff3e2d Mon Sep 17 00:00:00 2001 From: Iurii Makhno Date: Tue, 15 Feb 2022 20:02:52 +0000 Subject: [PATCH 1/2] Introduce ResourceNamedType that represents pair of name + ResourceType. This type will be used as part of ResourceName to support types with custom names inside aapt2. DD: go/custom-resource-types-in-aapt2 Bug: b/215108200 Test: Resource_test.cpp Change-Id: Ib09776e6b2f69fefb9724136a345dc25bea42573 --- tools/aapt2/Resource.cpp | 18 +++++ tools/aapt2/Resource.h | 128 ++++++++++++++++++++++++++++++++-- tools/aapt2/Resource_test.cpp | 103 +++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 4 deletions(-) diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp index 6364ccdd09e5c..0bb330e26e6fb 100644 --- a/tools/aapt2/Resource.cpp +++ b/tools/aapt2/Resource.cpp @@ -134,6 +134,24 @@ static const std::map sResourceTypeMap{ {"xml", ResourceType::kXml}, }; +ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t) { + return {to_string(t), t}; +} + +std::optional ParseResourceNamedType(const android::StringPiece& s) { + auto colon = std::find(s.begin(), s.end(), ':'); + const ResourceType* parsedType; + if (colon != s.end() && colon != std::prev(s.end())) { + parsedType = ParseResourceType(s.substr(s.begin(), colon)); + } else { + parsedType = ParseResourceType(s); + } + if (parsedType == nullptr) { + return std::nullopt; + } + return ResourceNamedTypeRef(s, *parsedType); +} + const ResourceType* ParseResourceType(const StringPiece& str) { auto iter = sResourceTypeMap.find(str); if (iter == std::end(sResourceTypeMap)) { diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index 307c21d9dc965..d394b24d9947a 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -19,22 +19,21 @@ #include #include +#include #include #include #include #include +#include "Source.h" #include "androidfw/ConfigDescription.h" #include "androidfw/StringPiece.h" #include "utils/JenkinsHash.h" -#include "Source.h" - namespace aapt { /** - * The various types of resource types available. Corresponds - * to the 'type' in package:type/entry. + * The various types of resource types available. */ enum class ResourceType { kAnim, @@ -77,6 +76,52 @@ android::StringPiece to_string(ResourceType type); */ const ResourceType* ParseResourceType(const android::StringPiece& str); +/** + * Pair of type name as in ResourceTable and actual resource type. + * Corresponds to the 'type' in package:type/entry. + * + * This is to support resource types with custom names inside resource tables. + */ +struct ResourceNamedType { + std::string name; + ResourceType type = ResourceType::kRaw; + + ResourceNamedType() = default; + ResourceNamedType(const android::StringPiece& n, ResourceType t); + + int compare(const ResourceNamedType& other) const; + + const std::string& to_string() const; +}; + +/** + * Same as ResourceNamedType, but uses StringPieces instead. + * Use this if you need to avoid copying and know that + * the lifetime of this object is shorter than that + * of the original string. + */ +struct ResourceNamedTypeRef { + android::StringPiece name; + ResourceType type = ResourceType::kRaw; + + ResourceNamedTypeRef() = default; + ResourceNamedTypeRef(const ResourceNamedTypeRef&) = default; + ResourceNamedTypeRef(ResourceNamedTypeRef&&) = default; + ResourceNamedTypeRef(const ResourceNamedType& rhs); // NOLINT(google-explicit-constructor) + ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t); + ResourceNamedTypeRef& operator=(const ResourceNamedTypeRef& rhs) = default; + ResourceNamedTypeRef& operator=(ResourceNamedTypeRef&& rhs) = default; + ResourceNamedTypeRef& operator=(const ResourceNamedType& rhs); + + ResourceNamedType ToResourceNamedType() const; + + std::string to_string() const; +}; + +ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t); + +std::optional ParseResourceNamedType(const android::StringPiece& s); + /** * A resource's name. This can uniquely identify * a resource in the ResourceTable. @@ -294,6 +339,81 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) return out << to_string(val); } +// +// ResourceNamedType implementation. +// +inline ResourceNamedType::ResourceNamedType(const android::StringPiece& n, ResourceType t) + : name(n.to_string()), type(t) { +} + +inline int ResourceNamedType::compare(const ResourceNamedType& other) const { + int cmp = static_cast(type) - static_cast(other.type); + if (cmp != 0) return cmp; + cmp = name.compare(other.name); + return cmp; +} + +inline const std::string& ResourceNamedType::to_string() const { + return name; +} + +inline bool operator<(const ResourceNamedType& lhs, const ResourceNamedType& rhs) { + return lhs.compare(rhs) < 0; +} + +inline bool operator==(const ResourceNamedType& lhs, const ResourceNamedType& rhs) { + return lhs.compare(rhs) == 0; +} + +inline bool operator!=(const ResourceNamedType& lhs, const ResourceNamedType& rhs) { + return lhs.compare(rhs) != 0; +} + +inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedType& val) { + return out << val.to_string(); +} + +// +// ResourceNamedTypeRef implementation. +// +inline ResourceNamedTypeRef::ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t) + : name(n), type(t) { +} + +inline ResourceNamedTypeRef::ResourceNamedTypeRef(const ResourceNamedType& rhs) + : name(rhs.name), type(rhs.type) { +} + +inline ResourceNamedTypeRef& ResourceNamedTypeRef::operator=(const ResourceNamedType& rhs) { + name = rhs.name; + type = rhs.type; + return *this; +} + +inline ResourceNamedType ResourceNamedTypeRef::ToResourceNamedType() const { + return ResourceNamedType(name, type); +} + +inline std::string ResourceNamedTypeRef::to_string() const { + return name.to_string(); +} + +inline bool operator<(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) { + return std::tie(lhs.type, lhs.name) < std::tie(rhs.type, rhs.name); +} + +inline bool operator==(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) { + return std::tie(lhs.type, lhs.name) == std::tie(rhs.type, rhs.name); +} + +inline bool operator!=(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) { + return std::tie(lhs.type, lhs.name) != std::tie(rhs.type, rhs.name); +} + +inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedTypeRef& val) { + return out << val.name; +} + // // ResourceName implementation. // diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp index c557f3c776544..2c55d1d548db9 100644 --- a/tools/aapt2/Resource_test.cpp +++ b/tools/aapt2/Resource_test.cpp @@ -18,6 +18,9 @@ #include "test/Test.h" +using ::testing::Eq; +using ::testing::Optional; + namespace aapt { TEST(ResourceTypeTest, ParseResourceTypes) { @@ -125,4 +128,104 @@ TEST(ResourceTypeTest, ParseResourceTypes) { EXPECT_EQ(type, nullptr); } +TEST(ResourceTypeTest, ParseResourceNamedType) { + auto type = ParseResourceNamedType("anim"); + EXPECT_THAT(type, Optional(Eq(ResourceNamedType("anim", ResourceType::kAnim)))); + + type = ParseResourceNamedType("layout"); + EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout", ResourceType::kLayout)))); + + type = ParseResourceNamedType("layout:2"); + EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:2", ResourceType::kLayout)))); + + type = ParseResourceNamedType("layout:another"); + EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:another", ResourceType::kLayout)))); + + type = ParseResourceNamedType("layout:"); + EXPECT_THAT(type, Eq(std::nullopt)); + + type = ParseResourceNamedType("layout2"); + EXPECT_THAT(type, Eq(std::nullopt)); + + type = ParseResourceNamedType("blahaha"); + EXPECT_THAT(type, Eq(std::nullopt)); +} + +TEST(ResourceTypeTest, ResourceNamedTypeWithDefaultName) { + auto type = ResourceNamedTypeWithDefaultName(ResourceType::kAnim); + EXPECT_THAT(type, Eq(ResourceNamedType("anim", ResourceType::kAnim))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kAnimator); + EXPECT_THAT(type, Eq(ResourceNamedType("animator", ResourceType::kAnimator))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kArray); + EXPECT_THAT(type, Eq(ResourceNamedType("array", ResourceType::kArray))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kAttr); + EXPECT_THAT(type, Eq(ResourceNamedType("attr", ResourceType::kAttr))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kAttrPrivate); + EXPECT_THAT(type, Eq(ResourceNamedType("^attr-private", ResourceType::kAttrPrivate))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kBool); + EXPECT_THAT(type, Eq(ResourceNamedType("bool", ResourceType::kBool))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kColor); + EXPECT_THAT(type, Eq(ResourceNamedType("color", ResourceType::kColor))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kConfigVarying); + EXPECT_THAT(type, Eq(ResourceNamedType("configVarying", ResourceType::kConfigVarying))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kDimen); + EXPECT_THAT(type, Eq(ResourceNamedType("dimen", ResourceType::kDimen))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kDrawable); + EXPECT_THAT(type, Eq(ResourceNamedType("drawable", ResourceType::kDrawable))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kFont); + EXPECT_THAT(type, Eq(ResourceNamedType("font", ResourceType::kFont))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kFraction); + EXPECT_THAT(type, Eq(ResourceNamedType("fraction", ResourceType::kFraction))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kId); + EXPECT_THAT(type, Eq(ResourceNamedType("id", ResourceType::kId))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kInteger); + EXPECT_THAT(type, Eq(ResourceNamedType("integer", ResourceType::kInteger))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kInterpolator); + EXPECT_THAT(type, Eq(ResourceNamedType("interpolator", ResourceType::kInterpolator))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kLayout); + EXPECT_THAT(type, Eq(ResourceNamedType("layout", ResourceType::kLayout))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kMenu); + EXPECT_THAT(type, Eq(ResourceNamedType("menu", ResourceType::kMenu))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kMipmap); + EXPECT_THAT(type, Eq(ResourceNamedType("mipmap", ResourceType::kMipmap))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kNavigation); + EXPECT_THAT(type, Eq(ResourceNamedType("navigation", ResourceType::kNavigation))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kPlurals); + EXPECT_THAT(type, Eq(ResourceNamedType("plurals", ResourceType::kPlurals))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kRaw); + EXPECT_THAT(type, Eq(ResourceNamedType("raw", ResourceType::kRaw))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kString); + EXPECT_THAT(type, Eq(ResourceNamedType("string", ResourceType::kString))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kStyle); + EXPECT_THAT(type, Eq(ResourceNamedType("style", ResourceType::kStyle))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kTransition); + EXPECT_THAT(type, Eq(ResourceNamedType("transition", ResourceType::kTransition))); + + type = ResourceNamedTypeWithDefaultName(ResourceType::kXml); + EXPECT_THAT(type, Eq(ResourceNamedType("xml", ResourceType::kXml))); +} + } // namespace aapt From cff10cec6cb6f406f71d42b064d527549cc0cca8 Mon Sep 17 00:00:00 2001 From: Iurii Makhno Date: Tue, 15 Feb 2022 19:33:50 +0000 Subject: [PATCH 2/2] Switch ResourceName to use ResourceNamedType instead of ResourceType. DD: go/custom-resource-types-in-aapt2 Bug: b/215108200 Test: Resource_test.cpp Change-Id: I0b97fc0024523700e01adce788bb934d388da288 --- tools/aapt2/Debug.cpp | 2 +- tools/aapt2/Resource.h | 29 +++++++--- tools/aapt2/ResourceParser.cpp | 53 +++++++++++-------- tools/aapt2/ResourceTable.cpp | 8 +-- tools/aapt2/ResourceUtils.cpp | 30 +++++------ tools/aapt2/ResourceValues.cpp | 4 +- tools/aapt2/cmd/Link.cpp | 2 +- tools/aapt2/compile/IdAssigner.cpp | 10 ++-- tools/aapt2/compile/XmlIdCollector.cpp | 2 +- .../format/binary/BinaryResourceParser.cpp | 10 ++-- tools/aapt2/java/JavaClassGenerator.cpp | 12 ++--- tools/aapt2/java/ProguardRules.cpp | 4 +- tools/aapt2/link/ReferenceLinker.cpp | 4 +- tools/aapt2/link/TableMerger.cpp | 2 +- tools/aapt2/process/SymbolTable.cpp | 8 +-- tools/aapt2/process/SymbolTable.h | 2 +- 16 files changed, 104 insertions(+), 78 deletions(-) diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 7103944bc12e0..f47d66ea5e87e 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -80,7 +80,7 @@ class ValueHeadlinePrinter : public ConstValueVisitor { printer_->Print(parent_name.package); printer_->Print(":"); } - printer_->Print(to_string(parent_name.type)); + printer_->Print(parent_name.type.to_string()); printer_->Print("/"); printer_->Print(parent_name.entry); if (parent_ref.id) { diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index d394b24d9947a..b41d8514230bb 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -128,10 +128,12 @@ std::optional ParseResourceNamedType(const android::String */ struct ResourceName { std::string package; - ResourceType type = ResourceType::kRaw; + ResourceNamedType type; std::string entry; ResourceName() = default; + ResourceName(const android::StringPiece& p, const ResourceNamedTypeRef& t, + const android::StringPiece& e); ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e); int compare(const ResourceName& other) const; @@ -148,13 +150,15 @@ struct ResourceName { */ struct ResourceNameRef { android::StringPiece package; - ResourceType type = ResourceType::kRaw; + ResourceNamedTypeRef type; android::StringPiece entry; ResourceNameRef() = default; ResourceNameRef(const ResourceNameRef&) = default; ResourceNameRef(ResourceNameRef&&) = default; ResourceNameRef(const ResourceName& rhs); // NOLINT(google-explicit-constructor) + ResourceNameRef(const android::StringPiece& p, const ResourceNamedTypeRef& t, + const android::StringPiece& e); ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e); ResourceNameRef& operator=(const ResourceNameRef& rhs) = default; ResourceNameRef& operator=(ResourceNameRef&& rhs) = default; @@ -418,14 +422,20 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedTypeRe // ResourceName implementation. // +inline ResourceName::ResourceName(const android::StringPiece& p, const ResourceNamedTypeRef& t, + const android::StringPiece& e) + : package(p.to_string()), type(t.ToResourceNamedType()), entry(e.to_string()) { +} + inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e) - : package(p.to_string()), type(t), entry(e.to_string()) {} + : ResourceName(p, ResourceNamedTypeWithDefaultName(t), e) { +} inline int ResourceName::compare(const ResourceName& other) const { int cmp = package.compare(other.package); if (cmp != 0) return cmp; - cmp = static_cast(type) - static_cast(other.type); + cmp = type.compare(other.type); if (cmp != 0) return cmp; cmp = entry.compare(other.entry); return cmp; @@ -461,9 +471,16 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs) : package(rhs.package), type(rhs.type), entry(rhs.entry) {} +inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, + const ResourceNamedTypeRef& t, + const android::StringPiece& e) + : package(p), type(t), entry(e) { +} + inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e) - : package(p), type(t), entry(e) {} + : ResourceNameRef(p, ResourceNamedTypeWithDefaultName(t), e) { +} inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) { package = rhs.package; @@ -520,7 +537,7 @@ struct hash { size_t operator()(const aapt::ResourceName& name) const { android::hash_t h = 0; h = android::JenkinsHashMix(h, static_cast(hash()(name.package))); - h = android::JenkinsHashMix(h, static_cast(name.type)); + h = android::JenkinsHashMix(h, static_cast(hash()(name.type.name))); h = android::JenkinsHashMix(h, static_cast(hash()(name.entry))); return static_cast(h); } diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 792a3066f4f6f..42715f9c35922 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -604,7 +604,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } - out_resource->name.type = ResourceType::kId; + out_resource->name.type = + ResourceNamedTypeWithDefaultName(ResourceType::kId).ToResourceNamedType(); out_resource->name.entry = maybe_name.value().to_string(); // Ids either represent a unique resource id or reference another resource id @@ -623,7 +624,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, // A null reference also means there is no inner element when ids are in the form: // out_resource->value = util::make_unique(); - } else if (!ref || ref->name.value().type != ResourceType::kId) { + } else if (!ref || ref->name.value().type.type != ResourceType::kId) { // If an inner element exists, the inner element must be a reference to another resource id diag_->Error(DiagMessage(out_resource->source) << "<" << parser->element_name() @@ -640,7 +641,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } - out_resource->name.type = ResourceType::kMacro; + out_resource->name.type = + ResourceNamedTypeWithDefaultName(ResourceType::kMacro).ToResourceNamedType(); out_resource->name.entry = maybe_name.value().to_string(); return ParseMacro(parser, out_resource); } @@ -656,7 +658,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } - out_resource->name.type = item_iter->second.type; + out_resource->name.type = + ResourceNamedTypeWithDefaultName(item_iter->second.type).ToResourceNamedType(); out_resource->name.entry = maybe_name.value().to_string(); // Only use the implied format of the type when there is no explicit format. @@ -699,7 +702,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, if (can_be_item) { // Try parsing the elementName (or type) as a resource. These shall only be // resources like 'layout' or 'xml' and they can only be references. - const ResourceType* parsed_type = ParseResourceType(resource_type); + std::optional parsed_type = ParseResourceNamedType(resource_type); if (parsed_type) { if (!maybe_name) { diag_->Error(DiagMessage(out_resource->source) @@ -708,7 +711,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } - out_resource->name.type = *parsed_type; + out_resource->name.type = parsed_type->ToResourceNamedType(); out_resource->name.entry = maybe_name.value().to_string(); out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString); if (!out_resource->value) { @@ -933,7 +936,7 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out return false; } - const ResourceType* parsed_type = ParseResourceType(maybe_type.value()); + std::optional parsed_type = ParseResourceNamedType(maybe_type.value()); if (!parsed_type) { diag_->Error(DiagMessage(out_resource->source) << "invalid resource type '" << maybe_type.value() @@ -941,7 +944,7 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out return false; } - out_resource->name.type = *parsed_type; + out_resource->name.type = parsed_type->ToResourceNamedType(); if (std::optional maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) { std::optional maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value()); @@ -953,7 +956,7 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out out_resource->id = maybe_id.value(); } - if (*parsed_type == ResourceType::kId) { + if (parsed_type->type == ResourceType::kId) { // An ID marked as public is also the definition of an ID. out_resource->value = util::make_unique(); } @@ -978,7 +981,7 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou return false; } - const ResourceType* parsed_type = ParseResourceType(maybe_type.value()); + std::optional parsed_type = ParseResourceNamedType(maybe_type.value()); if (!parsed_type) { diag->Error(DiagMessage(out_resource->source) << "invalid resource type '" << maybe_type.value() << "' in <" << tag_name << ">"); @@ -1096,7 +1099,7 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser, return false; } - const ResourceType* parsed_type = ParseResourceType(maybe_type.value()); + std::optional parsed_type = ParseResourceNamedType(maybe_type.value()); if (!parsed_type) { diag_->Error(DiagMessage(out_resource->source) << "invalid resource type '" << maybe_type.value() << "' in <" @@ -1104,7 +1107,7 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser, return false; } - out_resource->name.type = *parsed_type; + out_resource->name.type = parsed_type->ToResourceNamedType(); return true; } @@ -1208,8 +1211,8 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource continue; } - const ResourceType* type = ParseResourceType(item_type.value()); - if (type == nullptr) { + std::optional type = ParseResourceNamedType(item_type.value()); + if (!type) { diag_->Error(DiagMessage(element_source) << "invalid resource type '" << item_type.value() << "' in within an "); @@ -1223,7 +1226,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource overlayable_item.source = element_source; ParsedResource child_resource{}; - child_resource.name.type = *type; + child_resource.name.type = type->ToResourceNamedType(); child_resource.name.entry = item_name.value().to_string(); child_resource.overlayable_item = overlayable_item; out_resource->child_resources.push_back(std::move(child_resource)); @@ -1289,7 +1292,8 @@ bool ResourceParser::ParseAttr(xml::XmlPullParser* parser, bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak) { - out_resource->name.type = ResourceType::kAttr; + out_resource->name.type = + ResourceNamedTypeWithDefaultName(ResourceType::kAttr).ToResourceNamedType(); // Attributes only end up in default configuration. if (out_resource->config != ConfigDescription::DefaultConfig()) { @@ -1475,7 +1479,8 @@ std::optional ResourceParser::ParseEnumOrFlagItem(xml::XmlPul } return Attribute::Symbol{ - Reference(ResourceNameRef({}, ResourceType::kId, maybe_name.value())), + Reference(ResourceNameRef({}, ResourceNamedTypeWithDefaultName(ResourceType::kId), + maybe_name.value())), val.data, val.dataType}; } @@ -1509,7 +1514,7 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) { bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* parser, ParsedResource* out_resource) { - out_resource->name.type = type; + out_resource->name.type = ResourceNamedTypeWithDefaultName(type).ToResourceNamedType(); std::unique_ptr