diff options
-rw-r--r-- | tools/aapt2/Android.bp | 1 | ||||
-rw-r--r-- | tools/aapt2/ResourceTable.cpp | 3 | ||||
-rw-r--r-- | tools/aapt2/ResourceValues.cpp | 199 | ||||
-rw-r--r-- | tools/aapt2/ResourceValues.h | 71 | ||||
-rw-r--r-- | tools/aapt2/ResourceValues_test.cpp | 12 | ||||
-rw-r--r-- | tools/aapt2/ValueTransformer.cpp | 50 | ||||
-rw-r--r-- | tools/aapt2/ValueTransformer.h | 128 | ||||
-rw-r--r-- | tools/aapt2/ValueTransformer_inline.h | 47 | ||||
-rw-r--r-- | tools/aapt2/cmd/Link.cpp | 5 | ||||
-rw-r--r-- | tools/aapt2/compile/PseudolocaleGenerator.cpp | 3 | ||||
-rw-r--r-- | tools/aapt2/format/binary/TableFlattener_test.cpp | 5 | ||||
-rw-r--r-- | tools/aapt2/java/JavaClassGenerator_test.cpp | 6 | ||||
-rw-r--r-- | tools/aapt2/link/AutoVersioner.cpp | 3 | ||||
-rw-r--r-- | tools/aapt2/link/TableMerger.cpp | 11 | ||||
-rw-r--r-- | tools/aapt2/link/XmlCompatVersioner.cpp | 9 | ||||
-rw-r--r-- | tools/aapt2/split/TableSplitter.cpp | 4 | ||||
-rw-r--r-- | tools/aapt2/test/Context.h | 3 | ||||
-rw-r--r-- | tools/aapt2/xml/XmlDom.cpp | 3 |
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)); } |