summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt2/Android.bp1
-rw-r--r--tools/aapt2/ResourceTable.cpp3
-rw-r--r--tools/aapt2/ResourceValues.cpp199
-rw-r--r--tools/aapt2/ResourceValues.h71
-rw-r--r--tools/aapt2/ResourceValues_test.cpp12
-rw-r--r--tools/aapt2/ValueTransformer.cpp50
-rw-r--r--tools/aapt2/ValueTransformer.h128
-rw-r--r--tools/aapt2/ValueTransformer_inline.h47
-rw-r--r--tools/aapt2/cmd/Link.cpp5
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.cpp3
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp5
-rw-r--r--tools/aapt2/java/JavaClassGenerator_test.cpp6
-rw-r--r--tools/aapt2/link/AutoVersioner.cpp3
-rw-r--r--tools/aapt2/link/TableMerger.cpp11
-rw-r--r--tools/aapt2/link/XmlCompatVersioner.cpp9
-rw-r--r--tools/aapt2/split/TableSplitter.cpp4
-rw-r--r--tools/aapt2/test/Context.h3
-rw-r--r--tools/aapt2/xml/XmlDom.cpp3
18 files changed, 420 insertions, 143 deletions
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 3937cee99e3b..12dc156f75be 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -162,6 +162,7 @@ cc_library_host_static {
"Configuration.proto",
"Resources.proto",
"ResourcesInternal.proto",
+ "ValueTransformer.cpp",
],
proto: {
export_proto_headers: true,
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 27f7bdd83c9e..45ea65430bb6 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -577,6 +577,7 @@ Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNam
std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
std::unique_ptr<ResourceTable> new_table = util::make_unique<ResourceTable>();
+ CloningValueTransformer cloner(&new_table->string_pool);
for (const auto& pkg : packages) {
ResourceTablePackage* new_pkg = new_table->FindOrCreatePackage(pkg->name);
for (const auto& type : pkg->types) {
@@ -593,7 +594,7 @@ std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
for (const auto& config_value : entry->values) {
ResourceConfigValue* new_value =
new_entry->FindOrCreateValue(config_value->config, config_value->product);
- new_value->value.reset(config_value->value->Clone(&new_table->string_pool));
+ new_value->value = config_value->value->Transform(cloner);
}
}
}
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 4f0fa8ae29ba..574bd2e44a84 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -47,6 +47,14 @@ std::ostream& operator<<(std::ostream& out, const Value& value) {
return out;
}
+std::unique_ptr<Value> Value::Transform(ValueTransformer& transformer) const {
+ return std::unique_ptr<Value>(this->TransformValueImpl(transformer));
+}
+
+std::unique_ptr<Item> Item::Transform(ValueTransformer& transformer) const {
+ return std::unique_ptr<Item>(this->TransformItemImpl(transformer));
+}
+
template <typename Derived>
void BaseValue<Derived>::Accept(ValueVisitor* visitor) {
visitor->Visit(static_cast<Derived*>(this));
@@ -77,13 +85,6 @@ bool RawString::Equals(const Value* value) const {
return *this->value == *other->value;
}
-RawString* RawString::Clone(StringPool* new_pool) const {
- RawString* rs = new RawString(new_pool->MakeRef(value));
- rs->comment_ = comment_;
- rs->source_ = source_;
- return rs;
-}
-
bool RawString::Flatten(android::Res_value* out_value) const {
out_value->dataType = android::Res_value::TYPE_STRING;
out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
@@ -136,10 +137,6 @@ bool Reference::Flatten(android::Res_value* out_value) const {
return true;
}
-Reference* Reference::Clone(StringPool* /*new_pool*/) const {
- return new Reference(*this);
-}
-
void Reference::Print(std::ostream* out) const {
if (reference_type == Type::kResource) {
*out << "(reference) @";
@@ -220,10 +217,6 @@ bool Id::Flatten(android::Res_value* out) const {
return true;
}
-Id* Id::Clone(StringPool* /*new_pool*/) const {
- return new Id(*this);
-}
-
void Id::Print(std::ostream* out) const {
*out << "(id)";
}
@@ -266,14 +259,6 @@ bool String::Flatten(android::Res_value* out_value) const {
return true;
}
-String* String::Clone(StringPool* new_pool) const {
- String* str = new String(new_pool->MakeRef(value));
- str->comment_ = comment_;
- str->source_ = source_;
- str->untranslatable_sections = untranslatable_sections;
- return str;
-}
-
void String::Print(std::ostream* out) const {
*out << "(string) \"" << *value << "\"";
}
@@ -321,14 +306,6 @@ bool StyledString::Flatten(android::Res_value* out_value) const {
return true;
}
-StyledString* StyledString::Clone(StringPool* new_pool) const {
- StyledString* str = new StyledString(new_pool->MakeRef(value));
- str->comment_ = comment_;
- str->source_ = source_;
- str->untranslatable_sections = untranslatable_sections;
- return str;
-}
-
void StyledString::Print(std::ostream* out) const {
*out << "(styled string) \"" << value->value << "\"";
for (const StringPool::Span& span : value->spans) {
@@ -357,15 +334,6 @@ bool FileReference::Flatten(android::Res_value* out_value) const {
return true;
}
-FileReference* FileReference::Clone(StringPool* new_pool) const {
- FileReference* fr = new FileReference(new_pool->MakeRef(path));
- fr->file = file;
- fr->type = type;
- fr->comment_ = comment_;
- fr->source_ = source_;
- return fr;
-}
-
void FileReference::Print(std::ostream* out) const {
*out << "(file) " << *path;
switch (type) {
@@ -406,10 +374,6 @@ bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
return true;
}
-BinaryPrimitive* BinaryPrimitive::Clone(StringPool* /*new_pool*/) const {
- return new BinaryPrimitive(*this);
-}
-
void BinaryPrimitive::Print(std::ostream* out) const {
*out << StringPrintf("(primitive) type=0x%02x data=0x%08x", value.dataType, value.data);
}
@@ -587,10 +551,6 @@ bool Attribute::IsCompatibleWith(const Attribute& attr) const {
return this_type_mask == that_type_mask;
}
-Attribute* Attribute::Clone(StringPool* /*new_pool*/) const {
- return new Attribute(*this);
-}
-
std::string Attribute::MaskString() const {
if (type_mask == android::ResTable_map::TYPE_ANY) {
return "any";
@@ -893,18 +853,6 @@ bool Style::Equals(const Value* value) const {
});
}
-Style* Style::Clone(StringPool* new_pool) const {
- Style* style = new Style();
- style->parent = parent;
- style->parent_inferred = parent_inferred;
- style->comment_ = comment_;
- style->source_ = source_;
- for (auto& entry : entries) {
- style->entries.push_back(Entry{entry.key, std::unique_ptr<Item>(entry.value->Clone(new_pool))});
- }
- return style;
-}
-
void Style::Print(std::ostream* out) const {
*out << "(style) ";
if (parent && parent.value().name) {
@@ -920,7 +868,8 @@ void Style::Print(std::ostream* out) const {
Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) {
Style::Entry cloned_entry{entry.key};
if (entry.value != nullptr) {
- cloned_entry.value.reset(entry.value->Clone(pool));
+ CloningValueTransformer cloner(pool);
+ cloned_entry.value = entry.value->Transform(cloner);
}
return cloned_entry;
}
@@ -993,16 +942,6 @@ bool Array::Equals(const Value* value) const {
});
}
-Array* Array::Clone(StringPool* new_pool) const {
- Array* array = new Array();
- array->comment_ = comment_;
- array->source_ = source_;
- for (auto& item : elements) {
- array->elements.emplace_back(std::unique_ptr<Item>(item->Clone(new_pool)));
- }
- return array;
-}
-
void Array::Print(std::ostream* out) const {
*out << "(array) [" << util::Joiner(elements, ", ") << "]";
}
@@ -1030,19 +969,6 @@ bool Plural::Equals(const Value* value) const {
return true;
}
-Plural* Plural::Clone(StringPool* new_pool) const {
- Plural* p = new Plural();
- p->comment_ = comment_;
- p->source_ = source_;
- const size_t count = values.size();
- for (size_t i = 0; i < count; i++) {
- if (values[i]) {
- p->values[i] = std::unique_ptr<Item>(values[i]->Clone(new_pool));
- }
- }
- return p;
-}
-
void Plural::Print(std::ostream* out) const {
*out << "(plural)";
if (values[Zero]) {
@@ -1086,10 +1012,6 @@ bool Styleable::Equals(const Value* value) const {
});
}
-Styleable* Styleable::Clone(StringPool* /*new_pool*/) const {
- return new Styleable(*this);
-}
-
void Styleable::Print(std::ostream* out) const {
*out << "(styleable) "
<< " [" << util::Joiner(entries, ", ") << "]";
@@ -1126,4 +1048,105 @@ void Styleable::MergeWith(Styleable* other) {
entries.insert(entries.end(), references.begin(), references.end());
}
+template <typename T>
+std::unique_ptr<T> CopyValueFields(std::unique_ptr<T> new_value, const T* value) {
+ new_value->SetSource(value->GetSource());
+ new_value->SetComment(value->GetComment());
+ return new_value;
+}
+
+CloningValueTransformer::CloningValueTransformer(StringPool* new_pool)
+ : ValueTransformer(new_pool) {
+}
+
+std::unique_ptr<Reference> CloningValueTransformer::TransformDerived(const Reference* value) {
+ return std::make_unique<Reference>(*value);
+}
+
+std::unique_ptr<Id> CloningValueTransformer::TransformDerived(const Id* value) {
+ return std::make_unique<Id>(*value);
+}
+
+std::unique_ptr<RawString> CloningValueTransformer::TransformDerived(const RawString* value) {
+ auto new_value = std::make_unique<RawString>(pool_->MakeRef(value->value));
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<String> CloningValueTransformer::TransformDerived(const String* value) {
+ auto new_value = std::make_unique<String>(pool_->MakeRef(value->value));
+ new_value->untranslatable_sections = value->untranslatable_sections;
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<StyledString> CloningValueTransformer::TransformDerived(const StyledString* value) {
+ auto new_value = std::make_unique<StyledString>(pool_->MakeRef(value->value));
+ new_value->untranslatable_sections = value->untranslatable_sections;
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<FileReference> CloningValueTransformer::TransformDerived(
+ const FileReference* value) {
+ auto new_value = std::make_unique<FileReference>(pool_->MakeRef(value->path));
+ new_value->file = value->file;
+ new_value->type = value->type;
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<BinaryPrimitive> CloningValueTransformer::TransformDerived(
+ const BinaryPrimitive* value) {
+ return std::make_unique<BinaryPrimitive>(*value);
+}
+
+std::unique_ptr<Attribute> CloningValueTransformer::TransformDerived(const Attribute* value) {
+ auto new_value = std::make_unique<Attribute>();
+ new_value->type_mask = value->type_mask;
+ new_value->min_int = value->min_int;
+ new_value->max_int = value->max_int;
+ for (const Attribute::Symbol& s : value->symbols) {
+ new_value->symbols.emplace_back(Attribute::Symbol{
+ .symbol = *s.symbol.Transform(*this),
+ .value = s.value,
+ .type = s.type,
+ });
+ }
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<Style> CloningValueTransformer::TransformDerived(const Style* value) {
+ auto new_value = std::make_unique<Style>();
+ new_value->parent = value->parent;
+ new_value->parent_inferred = value->parent_inferred;
+ for (auto& entry : value->entries) {
+ new_value->entries.push_back(Style::Entry{entry.key, entry.value->Transform(*this)});
+ }
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<Array> CloningValueTransformer::TransformDerived(const Array* value) {
+ auto new_value = std::make_unique<Array>();
+ for (auto& item : value->elements) {
+ new_value->elements.emplace_back(item->Transform(*this));
+ }
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<Plural> CloningValueTransformer::TransformDerived(const Plural* value) {
+ auto new_value = std::make_unique<Plural>();
+ const size_t count = value->values.size();
+ for (size_t i = 0; i < count; i++) {
+ if (value->values[i]) {
+ new_value->values[i] = value->values[i]->Transform(*this);
+ }
+ }
+ return CopyValueFields(std::move(new_value), value);
+}
+
+std::unique_ptr<Styleable> CloningValueTransformer::TransformDerived(const Styleable* value) {
+ auto new_value = std::make_unique<Styleable>();
+ for (const Reference& s : value->entries) {
+ new_value->entries.emplace_back(*s.Transform(*this));
+ }
+ return CopyValueFields(std::move(new_value), value);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index fe0883be50aa..025864d385cf 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -28,6 +28,7 @@
#include "Diagnostics.h"
#include "Resource.h"
#include "StringPool.h"
+#include "ValueTransformer.h"
#include "io/File.h"
#include "text/Printer.h"
#include "util/Maybe.h"
@@ -100,9 +101,8 @@ class Value {
// Calls the appropriate overload of ConstValueVisitor.
virtual void Accept(ConstValueVisitor* visitor) const = 0;
- // Clone the value. `new_pool` is the new StringPool that
- // any resources with strings should use when copying their string.
- virtual Value* Clone(StringPool* new_pool) const = 0;
+ // Transform this Value into another Value using the transformer.
+ std::unique_ptr<Value> Transform(ValueTransformer& transformer) const;
// Human readable printout of this value.
virtual void Print(std::ostream* out) const = 0;
@@ -118,6 +118,9 @@ class Value {
std::string comment_;
bool weak_ = false;
bool translatable_ = true;
+
+ private:
+ virtual Value* TransformValueImpl(ValueTransformer& transformer) const = 0;
};
// Inherit from this to get visitor accepting implementations for free.
@@ -129,12 +132,15 @@ struct BaseValue : public Value {
// A resource item with a single value. This maps to android::ResTable_entry.
struct Item : public Value {
- // Clone the Item.
- virtual Item* Clone(StringPool* new_pool) const override = 0;
-
// Fills in an android::Res_value structure with this Item's binary representation.
// Returns false if an error occurred.
virtual bool Flatten(android::Res_value* out_value) const = 0;
+
+ // Transform this Item into another Item using the transformer.
+ std::unique_ptr<Item> Transform(ValueTransformer& transformer) const;
+
+ private:
+ virtual Item* TransformItemImpl(ValueTransformer& transformer) const = 0;
};
// Inherit from this to get visitor accepting implementations for free.
@@ -147,7 +153,7 @@ struct BaseItem : public Item {
// A reference to another resource. This maps to android::Res_value::TYPE_REFERENCE.
// A reference can be symbolic (with the name set to a valid resource name) or be
// numeric (the id is set to a valid resource ID).
-struct Reference : public BaseItem<Reference> {
+struct Reference : public TransformableItem<Reference, BaseItem<Reference>> {
enum class Type {
kResource,
kAttribute,
@@ -166,7 +172,6 @@ struct Reference : public BaseItem<Reference> {
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
- Reference* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
void PrettyPrint(text::Printer* printer) const override;
@@ -178,27 +183,25 @@ bool operator<(const Reference&, const Reference&);
bool operator==(const Reference&, const Reference&);
// An ID resource. Has no real value, just a place holder.
-struct Id : public BaseItem<Id> {
+struct Id : public TransformableItem<Id, BaseItem<Id>> {
Id() {
weak_ = true;
}
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out) const override;
- Id* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
};
// A raw, unprocessed string. This may contain quotations, escape sequences, and whitespace.
// This shall *NOT* end up in the final resource table.
-struct RawString : public BaseItem<RawString> {
+struct RawString : public TransformableItem<RawString, BaseItem<RawString>> {
StringPool::Ref value;
explicit RawString(const StringPool::Ref& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
- RawString* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
};
@@ -220,7 +223,7 @@ inline bool operator!=(const UntranslatableSection& a, const UntranslatableSecti
return a.start != b.start || a.end != b.end;
}
-struct String : public BaseItem<String> {
+struct String : public TransformableItem<String, BaseItem<String>> {
StringPool::Ref value;
// Sections of the string to NOT translate. Mainly used
@@ -232,12 +235,11 @@ struct String : public BaseItem<String> {
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
- String* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
void PrettyPrint(text::Printer* printer) const override;
};
-struct StyledString : public BaseItem<StyledString> {
+struct StyledString : public TransformableItem<StyledString, BaseItem<StyledString>> {
StringPool::StyleRef value;
// Sections of the string to NOT translate. Mainly used
@@ -249,11 +251,10 @@ struct StyledString : public BaseItem<StyledString> {
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
- StyledString* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
};
-struct FileReference : public BaseItem<FileReference> {
+struct FileReference : public TransformableItem<FileReference, BaseItem<FileReference>> {
StringPool::Ref path;
// A handle to the file object from which this file can be read.
@@ -269,12 +270,11 @@ struct FileReference : public BaseItem<FileReference> {
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
- FileReference* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
};
// Represents any other android::Res_value.
-struct BinaryPrimitive : public BaseItem<BinaryPrimitive> {
+struct BinaryPrimitive : public TransformableItem<BinaryPrimitive, BaseItem<BinaryPrimitive>> {
android::Res_value value;
BinaryPrimitive() = default;
@@ -283,12 +283,11 @@ struct BinaryPrimitive : public BaseItem<BinaryPrimitive> {
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
- BinaryPrimitive* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
void PrettyPrint(text::Printer* printer) const override;
};
-struct Attribute : public BaseValue<Attribute> {
+struct Attribute : public TransformableValue<Attribute, BaseValue<Attribute>> {
struct Symbol {
Reference symbol;
uint32_t value;
@@ -311,13 +310,12 @@ struct Attribute : public BaseValue<Attribute> {
// TYPE_ENUMS are never compatible.
bool IsCompatibleWith(const Attribute& attr) const;
- Attribute* Clone(StringPool* new_pool) const override;
std::string MaskString() const;
void Print(std::ostream* out) const override;
bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const;
};
-struct Style : public BaseValue<Style> {
+struct Style : public TransformableValue<Style, BaseValue<Style>> {
struct Entry {
Reference key;
std::unique_ptr<Item> value;
@@ -333,7 +331,6 @@ struct Style : public BaseValue<Style> {
std::vector<Entry> entries;
bool Equals(const Value* value) const override;
- Style* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
// Merges `style` into this Style. All identical attributes of `style` take precedence, including
@@ -341,29 +338,26 @@ struct Style : public BaseValue<Style> {
void MergeWith(Style* style, StringPool* pool);
};
-struct Array : public BaseValue<Array> {
+struct Array : public TransformableValue<Array, BaseValue<Array>> {
std::vector<std::unique_ptr<Item>> elements;
bool Equals(const Value* value) const override;
- Array* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
};
-struct Plural : public BaseValue<Plural> {
+struct Plural : public TransformableValue<Plural, BaseValue<Plural>> {
enum { Zero = 0, One, Two, Few, Many, Other, Count };
std::array<std::unique_ptr<Item>, Count> values;
bool Equals(const Value* value) const override;
- Plural* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
};
-struct Styleable : public BaseValue<Styleable> {
+struct Styleable : public TransformableValue<Styleable, BaseValue<Styleable>> {
std::vector<Reference> entries;
bool Equals(const Value* value) const override;
- Styleable* Clone(StringPool* newPool) const override;
void Print(std::ostream* out) const override;
void MergeWith(Styleable* styleable);
};
@@ -379,6 +373,23 @@ typename std::enable_if<std::is_base_of<Value, T>::value, std::ostream&>::type o
return out;
}
+struct CloningValueTransformer : public ValueTransformer {
+ explicit CloningValueTransformer(StringPool* new_pool);
+
+ std::unique_ptr<Reference> TransformDerived(const Reference* value) override;
+ std::unique_ptr<Id> TransformDerived(const Id* value) override;
+ std::unique_ptr<RawString> TransformDerived(const RawString* value) override;
+ std::unique_ptr<String> TransformDerived(const String* value) override;
+ std::unique_ptr<StyledString> TransformDerived(const StyledString* value) override;
+ std::unique_ptr<FileReference> TransformDerived(const FileReference* value) override;
+ std::unique_ptr<BinaryPrimitive> TransformDerived(const BinaryPrimitive* value) override;
+ std::unique_ptr<Attribute> TransformDerived(const Attribute* value) override;
+ std::unique_ptr<Style> TransformDerived(const Style* value) override;
+ std::unique_ptr<Array> TransformDerived(const Array* value) override;
+ std::unique_ptr<Plural> TransformDerived(const Plural* value) override;
+ std::unique_ptr<Styleable> TransformDerived(const Styleable* value) override;
+};
+
} // namespace aapt
#endif // AAPT_RESOURCE_VALUES_H
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index c4a1108ac62a..c75a4b99e138 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -62,7 +62,8 @@ TEST(ResourceValuesTest, PluralClone) {
a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
a.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other"));
- std::unique_ptr<Plural> b(a.Clone(&pool));
+ CloningValueTransformer cloner(&pool);
+ std::unique_ptr<Plural> b(a.Transform(cloner));
EXPECT_TRUE(a.Equals(b.get()));
}
@@ -97,7 +98,8 @@ TEST(ResourceValuesTest, ArrayClone) {
a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
a.elements.push_back(util::make_unique<String>(pool.MakeRef("two")));
- std::unique_ptr<Array> b(a.Clone(&pool));
+ CloningValueTransformer cloner(&pool);
+ std::unique_ptr<Array> b(a.Transform(cloner));
EXPECT_TRUE(a.Equals(b.get()));
}
@@ -160,7 +162,8 @@ TEST(ResourceValuesTest, StyleClone) {
.AddItem("android:attr/bar", ResourceUtils::TryParseInt("2"))
.Build();
- std::unique_ptr<Style> b(a->Clone(nullptr));
+ CloningValueTransformer cloner(nullptr);
+ std::unique_ptr<Style> b(a->Transform(cloner));
EXPECT_TRUE(a->Equals(b.get()));
}
@@ -174,7 +177,8 @@ TEST(ResourcesValuesTest, StringClones) {
EXPECT_THAT(pool_a.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
EXPECT_THAT(pool_a.strings()[0]->value, StrEq("hello"));
- std::unique_ptr<String> str_b(str_a.Clone(&pool_b));
+ CloningValueTransformer cloner(&pool_b);
+ str_a.Transform(cloner);
ASSERT_THAT(pool_b, SizeIs(1u));
EXPECT_THAT(pool_b.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
EXPECT_THAT(pool_b.strings()[0]->value, StrEq("hello"));
diff --git a/tools/aapt2/ValueTransformer.cpp b/tools/aapt2/ValueTransformer.cpp
new file mode 100644
index 000000000000..6eb2e30fb923
--- /dev/null
+++ b/tools/aapt2/ValueTransformer.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ValueTransformer.h"
+
+#include "ResourceValues.h"
+
+namespace aapt {
+
+#define VALUE_CREATE_VALUE_DECL(T) \
+ std::unique_ptr<Value> ValueTransformer::TransformValue(const T* value) { \
+ return TransformDerived(value); \
+ }
+
+#define VALUE_CREATE_ITEM_DECL(T) \
+ std::unique_ptr<Item> ValueTransformer::TransformItem(const T* value) { \
+ return TransformDerived(value); \
+ } \
+ std::unique_ptr<Value> ValueTransformer::TransformValue(const T* value) { \
+ return TransformItem(value); \
+ }
+
+VALUE_CREATE_ITEM_DECL(Id);
+VALUE_CREATE_ITEM_DECL(Reference);
+VALUE_CREATE_ITEM_DECL(RawString);
+VALUE_CREATE_ITEM_DECL(String);
+VALUE_CREATE_ITEM_DECL(StyledString);
+VALUE_CREATE_ITEM_DECL(FileReference);
+VALUE_CREATE_ITEM_DECL(BinaryPrimitive);
+
+VALUE_CREATE_VALUE_DECL(Attribute);
+VALUE_CREATE_VALUE_DECL(Style);
+VALUE_CREATE_VALUE_DECL(Array);
+VALUE_CREATE_VALUE_DECL(Plural);
+VALUE_CREATE_VALUE_DECL(Styleable);
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/ValueTransformer.h b/tools/aapt2/ValueTransformer.h
new file mode 100644
index 000000000000..692511132012
--- /dev/null
+++ b/tools/aapt2/ValueTransformer.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_VALUE_TRANSFORMER_H
+#define AAPT_VALUE_TRANSFORMER_H
+
+#include <memory>
+
+#include "StringPool.h"
+
+namespace aapt {
+
+class Value;
+struct Item;
+struct Reference;
+struct Id;
+struct RawString;
+struct String;
+struct StyledString;
+struct FileReference;
+struct BinaryPrimitive;
+struct Attribute;
+struct Style;
+struct Array;
+struct Plural;
+struct Styleable;
+
+#define AAPT_TRANSFORM_VALUE(T) \
+ virtual std::unique_ptr<T> TransformDerived(const T* value) = 0; \
+ virtual std::unique_ptr<Value> TransformValue(const T* value);
+
+#define AAPT_TRANSFORM_ITEM(T) \
+ virtual std::unique_ptr<Item> TransformItem(const T* value); \
+ AAPT_TRANSFORM_VALUE(T)
+
+/**
+ * An interface for consuming a Value type and transforming it into another Value.
+ *
+ * The interface defines 2 methods for each type (T) that inherits from TransformableValue:
+ * std::unique_ptr<T> TransformDerived(const T*)
+ * std::unique_ptr<Value> TransformValue(const T*)
+ *
+ * The interface defines 3 method for each type (T) that inherits from TransformableItem:
+ * std::unique_ptr<T> TransformDerived(const T*)
+ * std::unique_ptr<Item> TransformItem(const T*)
+ * std::unique_ptr<Value> TransformValue(const T*)
+ *
+ * TransformDerived is invoked when Transform is invoked on the derived type T.
+ * TransformItem is invoked when Transform is invoked on an Item type.
+ * TransformValue is invoked when Transform is invoked on a Value type.
+ *
+ * ValueTransformerImpl transformer(&string_pool);
+ * T* derived = ...;
+ * std::unique_ptr<T> new_type = derived->Transform(transformer); // Invokes TransformDerived
+ *
+ * Item* item = derived;
+ * std::unique_ptr<Item> new_item = item->TransformItem(transformer); // Invokes TransformItem
+ *
+ * Value* value = item;
+ * std::unique_ptr<Value> new_value = value->TransformValue(transformer); // Invokes TransformValue
+ *
+ * For types that inherit from AbstractTransformableItem, the default implementation of
+ * TransformValue invokes TransformItem which invokes TransformDerived.
+ *
+ * For types that inherit from AbstractTransformableValue, the default implementation of
+ * TransformValue invokes TransformDerived.
+ */
+struct ValueTransformer {
+ // `new_pool` is the new StringPool that newly created Values should use for string storing string
+ // values.
+ explicit ValueTransformer(StringPool* new_pool);
+ virtual ~ValueTransformer() = default;
+
+ AAPT_TRANSFORM_ITEM(Id);
+ AAPT_TRANSFORM_ITEM(Reference);
+ AAPT_TRANSFORM_ITEM(RawString);
+ AAPT_TRANSFORM_ITEM(String);
+ AAPT_TRANSFORM_ITEM(StyledString);
+ AAPT_TRANSFORM_ITEM(FileReference);
+ AAPT_TRANSFORM_ITEM(BinaryPrimitive);
+
+ AAPT_TRANSFORM_VALUE(Attribute);
+ AAPT_TRANSFORM_VALUE(Style);
+ AAPT_TRANSFORM_VALUE(Array);
+ AAPT_TRANSFORM_VALUE(Plural);
+ AAPT_TRANSFORM_VALUE(Styleable);
+
+ protected:
+ StringPool* const pool_;
+};
+
+#undef AAPT_TRANSFORM_VALUE
+#undef AAPT_TRANSFORM_ITEM
+
+template <typename Derived, typename Base>
+struct TransformableValue : public Base {
+ // Transform this Derived into another Derived using the transformer.
+ std::unique_ptr<Derived> Transform(ValueTransformer& transformer) const;
+
+ private:
+ Value* TransformValueImpl(ValueTransformer& transformer) const override;
+};
+
+template <typename Derived, typename Base>
+struct TransformableItem : public TransformableValue<Derived, Base> {
+ private:
+ Item* TransformItemImpl(ValueTransformer& transformer) const override;
+};
+
+} // namespace aapt
+
+// Implementation
+#include "ValueTransformer_inline.h"
+
+#endif // AAPT_VALUE_TRANSFORMER_H \ No newline at end of file
diff --git a/tools/aapt2/ValueTransformer_inline.h b/tools/aapt2/ValueTransformer_inline.h
new file mode 100644
index 000000000000..c6c07c0fd6f9
--- /dev/null
+++ b/tools/aapt2/ValueTransformer_inline.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_VALUE_TRANSFORMER_IMPL_H
+#define AAPT_VALUE_TRANSFORMER_IMPL_H
+
+namespace aapt {
+
+inline ValueTransformer::ValueTransformer(StringPool* new_pool) : pool_(new_pool) {
+}
+
+template <typename Derived, typename Base>
+inline std::unique_ptr<Derived> TransformableValue<Derived, Base>::Transform(
+ ValueTransformer& transformer) const {
+ return transformer.TransformDerived(static_cast<const Derived*>(this));
+}
+
+template <typename Derived, typename Base>
+Value* TransformableValue<Derived, Base>::TransformValueImpl(ValueTransformer& transformer) const {
+ auto self = static_cast<const Derived*>(this);
+ auto transformed = transformer.TransformValue(self);
+ return transformed.release();
+}
+
+template <typename Derived, typename Base>
+Item* TransformableItem<Derived, Base>::TransformItemImpl(ValueTransformer& transformer) const {
+ auto self = static_cast<const Derived*>(this);
+ auto transformed = transformer.TransformItem(self);
+ return transformed.release();
+}
+
+} // namespace aapt
+
+#endif // AAPT_VALUE_TRANSFORMER_IMPL_H \ No newline at end of file
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 2a8923d927f6..2c57fb2b003e 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1656,10 +1656,11 @@ class Linker {
<< " with config \"" << config_value->config
<< "\" for round icon compatibility");
- auto value = icon_reference->Clone(&table->string_pool);
+ CloningValueTransformer cloner(&table->string_pool);
+ auto value = icon_reference->Transform(cloner);
auto round_config_value =
round_icon_entry->FindOrCreateValue(config_value->config, config_value->product);
- round_config_value->value.reset(value);
+ round_config_value->value = std::move(value);
}
}
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 5e0300b3071b..3f574ee8e897 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -226,6 +226,7 @@ class Visitor : public ValueVisitor {
: pool_(pool), method_(method), localizer_(method) {}
void Visit(Plural* plural) override {
+ CloningValueTransformer cloner(pool_);
std::unique_ptr<Plural> localized = util::make_unique<Plural>();
for (size_t i = 0; i < plural->values.size(); i++) {
Visitor sub_visitor(pool_, method_);
@@ -234,7 +235,7 @@ class Visitor : public ValueVisitor {
if (sub_visitor.item) {
localized->values[i] = std::move(sub_visitor.item);
} else {
- localized->values[i] = std::unique_ptr<Item>(plural->values[i]->Clone(pool_));
+ localized->values[i] = plural->values[i]->Transform(cloner);
}
}
}
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index f5fe5e30bf0f..8139d7385092 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -299,6 +299,7 @@ static std::unique_ptr<ResourceTable> BuildTableWithSparseEntries(
.Build();
// Add regular entries.
+ CloningValueTransformer cloner(&table->string_pool);
int stride = static_cast<int>(1.0f / load);
for (int i = 0; i < 100; i++) {
const ResourceName name = test::ParseNameOrDie(
@@ -308,7 +309,7 @@ static std::unique_ptr<ResourceTable> BuildTableWithSparseEntries(
util::make_unique<BinaryPrimitive>(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(i));
CHECK(table->AddResource(NewResourceBuilder(name)
.SetId(resid)
- .SetValue(std::unique_ptr<Value>(value->Clone(nullptr)))
+ .SetValue(std::unique_ptr<Value>(value->Transform(cloner)))
.Build(),
context->GetDiagnostics()));
@@ -317,7 +318,7 @@ static std::unique_ptr<ResourceTable> BuildTableWithSparseEntries(
CHECK(table->AddResource(
NewResourceBuilder(name)
.SetId(resid)
- .SetValue(std::unique_ptr<Value>(value->Clone(nullptr)), sparse_config)
+ .SetValue(std::unique_ptr<Value>(value->Transform(cloner)), sparse_config)
.Build(),
context->GetDiagnostics()));
}
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 8bb3ee93d312..d08b61e5ff66 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -334,11 +334,12 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent)
styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
styleable.SetComment(StringPiece("This is a styleable"));
+ CloningValueTransformer cloner(nullptr);
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.AddValue("android:attr/one", util::make_unique<Attribute>(attr))
.AddValue("android:styleable/Container",
- std::unique_ptr<Styleable>(styleable.Clone(nullptr)))
+ std::unique_ptr<Styleable>(styleable.Transform(cloner)))
.Build();
std::unique_ptr<IAaptContext> context =
@@ -371,11 +372,12 @@ TEST(JavaClassGeneratorTest, CommentsForStyleableHiddenAttributesAreNotPresent)
styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
styleable.SetComment(StringPiece("This is a styleable"));
+ CloningValueTransformer cloner(nullptr);
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.AddValue("android:attr/one", util::make_unique<Attribute>(attr))
.AddValue("android:styleable/Container",
- std::unique_ptr<Styleable>(styleable.Clone(nullptr)))
+ std::unique_ptr<Styleable>(styleable.Transform(cloner)))
.Build();
std::unique_ptr<IAaptContext> context =
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index 73b92542a755..876494e617a6 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -72,6 +72,7 @@ ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry,
bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) {
TRACE_NAME("AutoVersioner::Consume");
+ CloningValueTransformer cloner(&table->string_pool);
for (auto& package : table->packages) {
for (auto& type : package->types) {
if (type->type != ResourceType::kStyle) {
@@ -128,7 +129,7 @@ bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) {
ConfigDescription new_config(config_value->config);
new_config.sdkVersion = static_cast<uint16_t>(min_sdk_stripped.value());
- std::unique_ptr<Style> new_style(style->Clone(&table->string_pool));
+ std::unique_ptr<Style> new_style(style->Transform(cloner));
new_style->SetComment(style->GetComment());
new_style->SetSource(style->GetSource());
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 4ef2882ce347..bc93ec6908e7 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -280,13 +280,13 @@ bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package,
}
// Continue if we're taking the new resource.
-
+ CloningValueTransformer cloner(&main_table_->string_pool);
if (FileReference* f = ValueCast<FileReference>(src_config_value->value.get())) {
std::unique_ptr<FileReference> new_file_ref;
if (mangle_package) {
new_file_ref = CloneAndMangleFile(src_package->name, *f);
} else {
- new_file_ref = std::unique_ptr<FileReference>(f->Clone(&main_table_->string_pool));
+ new_file_ref = std::unique_ptr<FileReference>(f->Transform(cloner));
}
dst_config_value->value = std::move(new_file_ref);
@@ -294,8 +294,7 @@ bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package,
Maybe<std::string> original_comment = (dst_config_value->value)
? dst_config_value->value->GetComment() : Maybe<std::string>();
- dst_config_value->value = std::unique_ptr<Value>(
- src_config_value->value->Clone(&main_table_->string_pool));
+ dst_config_value->value = src_config_value->value->Transform(cloner);
// Keep the comment from the original resource and ignore all comments from overlaying
// resources
@@ -323,7 +322,9 @@ std::unique_ptr<FileReference> TableMerger::CloneAndMangleFile(
new_file_ref->file = file_ref.file;
return new_file_ref;
}
- return std::unique_ptr<FileReference>(file_ref.Clone(&main_table_->string_pool));
+
+ CloningValueTransformer cloner(&main_table_->string_pool);
+ return std::unique_ptr<FileReference>(file_ref.Transform(cloner));
}
bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFile* file) {
diff --git a/tools/aapt2/link/XmlCompatVersioner.cpp b/tools/aapt2/link/XmlCompatVersioner.cpp
index 6937ca961f06..957b64cd8dbb 100644
--- a/tools/aapt2/link/XmlCompatVersioner.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner.cpp
@@ -23,9 +23,10 @@
namespace aapt {
static xml::Attribute CopyAttr(const xml::Attribute& src, StringPool* out_string_pool) {
+ CloningValueTransformer cloner(out_string_pool);
xml::Attribute dst{src.namespace_uri, src.name, src.value, src.compiled_attribute};
if (src.compiled_value != nullptr) {
- dst.compiled_value.reset(src.compiled_value->Clone(out_string_pool));
+ dst.compiled_value = src.compiled_value->Transform(cloner);
}
return dst;
}
@@ -34,6 +35,7 @@ static xml::Attribute CopyAttr(const xml::Attribute& src, StringPool* out_string
// (came from a rule).
static bool CopyAttribute(const xml::Attribute& src_attr, bool generated, xml::Element* dst_el,
StringPool* out_string_pool) {
+ CloningValueTransformer cloner(out_string_pool);
xml::Attribute* dst_attr = dst_el->FindAttribute(src_attr.namespace_uri, src_attr.name);
if (dst_attr != nullptr) {
if (generated) {
@@ -41,7 +43,7 @@ static bool CopyAttribute(const xml::Attribute& src_attr, bool generated, xml::E
dst_attr->value = src_attr.value;
dst_attr->compiled_attribute = src_attr.compiled_attribute;
if (src_attr.compiled_value != nullptr) {
- dst_attr->compiled_value.reset(src_attr.compiled_value->Clone(out_string_pool));
+ dst_attr->compiled_value = src_attr.compiled_value->Transform(cloner);
}
return true;
}
@@ -158,7 +160,8 @@ static inline std::unique_ptr<Item> CloneIfNotNull(const std::unique_ptr<Item>&
if (src == nullptr) {
return {};
}
- return std::unique_ptr<Item>(src->Clone(out_string_pool));
+ CloningValueTransformer cloner(out_string_pool);
+ return src->Transform(cloner);
}
std::vector<DegradeResult> DegradeToManyRule::Degrade(const xml::Element& src_el,
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 2f319b11e3b2..116b2ab9aa98 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -229,6 +229,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
for (size_t idx = 0; idx < split_count; idx++) {
const SplitConstraints& split_constraint = split_constraints_[idx];
ResourceTable* split_table = splits_[idx].get();
+ CloningValueTransformer cloner(&split_table->string_pool);
// Select the values we want from this entry for this split.
SplitValueSelector selector(split_constraint);
@@ -254,8 +255,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
for (ResourceConfigValue* config_value : selected_values) {
ResourceConfigValue* new_config_value =
split_entry->FindOrCreateValue(config_value->config, config_value->product);
- new_config_value->value = std::unique_ptr<Value>(
- config_value->value->Clone(&split_table->string_pool));
+ new_config_value->value = config_value->value->Transform(cloner);
}
}
}
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 553c43e6c469..5d8ded39e654 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -200,10 +200,11 @@ class StaticSymbolSourceBuilder {
private:
std::unique_ptr<SymbolTable::Symbol> CloneSymbol(SymbolTable::Symbol* sym) {
+ CloningValueTransformer cloner(nullptr);
std::unique_ptr<SymbolTable::Symbol> clone = util::make_unique<SymbolTable::Symbol>();
clone->id = sym->id;
if (sym->attribute) {
- clone->attribute = std::unique_ptr<Attribute>(sym->attribute->Clone(nullptr));
+ clone->attribute = std::unique_ptr<Attribute>(sym->attribute->Transform(cloner));
}
clone->is_public = sym->is_public;
return clone;
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 005eeb936612..2cdcfe45b50e 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -374,6 +374,7 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
std::unique_ptr<XmlResource> XmlResource::Clone() const {
std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
+ CloningValueTransformer cloner(&cloned->string_pool);
if (root != nullptr) {
cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
dst->attributes.reserve(src.attributes.size());
@@ -384,7 +385,7 @@ std::unique_ptr<XmlResource> XmlResource::Clone() const {
cloned_attr.value = attr.value;
cloned_attr.compiled_attribute = attr.compiled_attribute;
if (attr.compiled_value != nullptr) {
- cloned_attr.compiled_value.reset(attr.compiled_value->Clone(&cloned->string_pool));
+ cloned_attr.compiled_value = attr.compiled_value->Transform(cloner);
}
dst->attributes.push_back(std::move(cloned_attr));
}