Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efcdb95f authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

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
parent 41d65a1b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ cc_library_host_static {
        "Configuration.proto",
        "Resources.proto",
        "ResourcesInternal.proto",
        "ValueTransformer.cpp",
    ],
    proto: {
        export_proto_headers: true,
+2 −1
Original line number Diff line number Diff line
@@ -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);
        }
      }
    }
+111 −88
Original line number Diff line number Diff line
@@ -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
+41 −30
Original line number Diff line number Diff line
@@ -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
+8 −4
Original line number Diff line number Diff line
@@ -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"));
Loading