AAPT2: Allow undefined resources (placeholders)
A resource defined like so:
<item type="drawable" name="foo" />
should be assigned the value @null.
The only exception is for <string> resources, which are given the
empty string value (since <string></string> is ambiguous). The decision
to use "" is based off the fact that old AAPT used to assign "" to all
undefined resources, even non-string ones.
Bug: 38425050
Test: make aapt2_tests
Change-Id: Ib3e0f6f83d16ddd8b279c9fd44a07a37867b85e9
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 818c8ce..deeef6e 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -305,21 +305,25 @@
return {};
}
-std::unique_ptr<BinaryPrimitive> TryParseNullOrEmpty(const StringPiece& str) {
- StringPiece trimmed_str(util::TrimWhitespace(str));
- android::Res_value value = {};
+std::unique_ptr<Item> TryParseNullOrEmpty(const StringPiece& str) {
+ const StringPiece trimmed_str(util::TrimWhitespace(str));
if (trimmed_str == "@null") {
- // TYPE_NULL with data set to 0 is interpreted by the runtime as an error.
- // Instead we set the data type to TYPE_REFERENCE with a value of 0.
- value.dataType = android::Res_value::TYPE_REFERENCE;
+ return MakeNull();
} else if (trimmed_str == "@empty") {
- // TYPE_NULL with value of DATA_NULL_EMPTY is handled fine by the runtime.
- value.dataType = android::Res_value::TYPE_NULL;
- value.data = android::Res_value::DATA_NULL_EMPTY;
- } else {
- return {};
+ return MakeEmpty();
}
- return util::make_unique<BinaryPrimitive>(value);
+ return {};
+}
+
+std::unique_ptr<Reference> MakeNull() {
+ // TYPE_NULL with data set to 0 is interpreted by the runtime as an error.
+ // Instead we set the data type to TYPE_REFERENCE with a value of 0.
+ return util::make_unique<Reference>();
+}
+
+std::unique_ptr<BinaryPrimitive> MakeEmpty() {
+ return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_NULL,
+ android::Res_value::DATA_NULL_EMPTY);
}
std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
@@ -569,13 +573,15 @@
std::unique_ptr<Item> TryParseItemForAttribute(
const StringPiece& value, uint32_t type_mask,
const std::function<void(const ResourceName&)>& on_create_reference) {
- std::unique_ptr<BinaryPrimitive> null_or_empty = TryParseNullOrEmpty(value);
+ using android::ResTable_map;
+
+ auto null_or_empty = TryParseNullOrEmpty(value);
if (null_or_empty) {
- return std::move(null_or_empty);
+ return null_or_empty;
}
bool create = false;
- std::unique_ptr<Reference> reference = TryParseReference(value, &create);
+ auto reference = TryParseReference(value, &create);
if (reference) {
if (create && on_create_reference) {
on_create_reference(reference->name.value());
@@ -583,39 +589,37 @@
return std::move(reference);
}
- if (type_mask & android::ResTable_map::TYPE_COLOR) {
+ if (type_mask & ResTable_map::TYPE_COLOR) {
// Try parsing this as a color.
- std::unique_ptr<BinaryPrimitive> color = TryParseColor(value);
+ auto color = TryParseColor(value);
if (color) {
return std::move(color);
}
}
- if (type_mask & android::ResTable_map::TYPE_BOOLEAN) {
+ if (type_mask & ResTable_map::TYPE_BOOLEAN) {
// Try parsing this as a boolean.
- std::unique_ptr<BinaryPrimitive> boolean = TryParseBool(value);
+ auto boolean = TryParseBool(value);
if (boolean) {
return std::move(boolean);
}
}
- if (type_mask & android::ResTable_map::TYPE_INTEGER) {
+ if (type_mask & ResTable_map::TYPE_INTEGER) {
// Try parsing this as an integer.
- std::unique_ptr<BinaryPrimitive> integer = TryParseInt(value);
+ auto integer = TryParseInt(value);
if (integer) {
return std::move(integer);
}
}
- const uint32_t float_mask = android::ResTable_map::TYPE_FLOAT |
- android::ResTable_map::TYPE_DIMENSION |
- android::ResTable_map::TYPE_FRACTION;
+ const uint32_t float_mask =
+ ResTable_map::TYPE_FLOAT | ResTable_map::TYPE_DIMENSION | ResTable_map::TYPE_FRACTION;
if (type_mask & float_mask) {
// Try parsing this as a float.
- std::unique_ptr<BinaryPrimitive> floating_point = TryParseFloat(value);
+ auto floating_point = TryParseFloat(value);
if (floating_point) {
- if (type_mask &
- AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) {
+ if (type_mask & AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) {
return std::move(floating_point);
}
}
@@ -630,24 +634,25 @@
std::unique_ptr<Item> TryParseItemForAttribute(
const StringPiece& str, const Attribute* attr,
const std::function<void(const ResourceName&)>& on_create_reference) {
+ using android::ResTable_map;
+
const uint32_t type_mask = attr->type_mask;
- std::unique_ptr<Item> value =
- TryParseItemForAttribute(str, type_mask, on_create_reference);
+ auto value = TryParseItemForAttribute(str, type_mask, on_create_reference);
if (value) {
return value;
}
- if (type_mask & android::ResTable_map::TYPE_ENUM) {
+ if (type_mask & ResTable_map::TYPE_ENUM) {
// Try parsing this as an enum.
- std::unique_ptr<BinaryPrimitive> enum_value = TryParseEnumSymbol(attr, str);
+ auto enum_value = TryParseEnumSymbol(attr, str);
if (enum_value) {
return std::move(enum_value);
}
}
- if (type_mask & android::ResTable_map::TYPE_FLAGS) {
+ if (type_mask & ResTable_map::TYPE_FLAGS) {
// Try parsing this as a flag.
- std::unique_ptr<BinaryPrimitive> flag_value = TryParseFlagSymbol(attr, str);
+ auto flag_value = TryParseFlagSymbol(attr, str);
if (flag_value) {
return std::move(flag_value);
}
@@ -655,8 +660,7 @@
return {};
}
-std::string BuildResourceFileName(const ResourceFile& res_file,
- const NameMangler* mangler) {
+std::string BuildResourceFileName(const ResourceFile& res_file, const NameMangler* mangler) {
std::stringstream out;
out << "res/" << res_file.name.type;
if (res_file.config != ConfigDescription{}) {
@@ -719,9 +723,9 @@
ref_type = Reference::Type::kAttribute;
}
- if (data == 0) {
+ if (data == 0u) {
// A reference of 0, must be the magic @null reference.
- return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_REFERENCE, 0u);
+ return util::make_unique<Reference>();
}
// This is a normal reference.