Aapt2 ValueTransformer
For future macro support, aapt2 must be able to convert Reference
values into other Value types. Currently a DescendingValueVisitor is
used to visit all of the References in a ResourceTable or a compiled
XML file to set their resource ids during the link phase. This was fine
since we were only mutating the resource id of the visited Reference.
A macro may reference a String, BinaryPrimitive, or any other Item
type. During the link phase, we will need to transform references to
macros into the values of the macros.
The only parameter in the methods of the ValueVisitor interface is a
raw pointer to the type being visited. The visitor interface does not
support reassigning the visited type to a different type.
ValueTransformer is a new interface for consuming a Value type and
transforming it into a compatible Value type. This change refactors
Value::Clone to use this interface.
Bug: 175616308
Test: aapt2_tests
Change-Id: Ic1b9d718b932c208764114cd9c74d880e189ccb0
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 3937cee..12dc156 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -162,6 +162,7 @@
"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 27f7bdd..45ea654 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -577,6 +577,7 @@
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 @@
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 4f0fa8a..574bd2e 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -47,6 +47,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
});
}
-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 @@
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 @@
});
}
-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 @@
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 @@
});
}
-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 @@
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 fe0883b..025864d 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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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&);
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 c4a1108..c75a4b9 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -62,7 +62,8 @@
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 @@
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 @@
.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 @@
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 0000000..6eb2e30
--- /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 0000000..6925111
--- /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 0000000..c6c07c0
--- /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 2a8923d..2c57fb2 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1656,10 +1656,11 @@
<< " 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 5e0300b..3f574ee 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -226,6 +226,7 @@
: 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 @@
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 f5fe5e3..8139d73 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -299,6 +299,7 @@
.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 @@
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 @@
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 8bb3ee9..d08b61e 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -334,11 +334,12 @@
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 @@
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 73b9254..876494e 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -72,6 +72,7 @@
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 @@
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 4ef2882..bc93ec6 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -280,13 +280,13 @@
}
// 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 @@
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 @@
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 6937ca9..957b64c 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 @@
// (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 @@
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 @@
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 2f319b1..116b2ab9 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -229,6 +229,7 @@
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 @@
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 553c43e..5d8ded3 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -200,10 +200,11 @@
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 005eeb9..2cdcfe4 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -374,6 +374,7 @@
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 @@
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));
}