summaryrefslogtreecommitdiff
path: root/tools/aapt2/ResourceParser.cpp
diff options
context:
space:
mode:
author Ryan Mitchell <rtmitchell@google.com> 2021-03-22 09:31:00 -0700
committer Ryan Mitchell <rtmitchell@google.com> 2021-03-29 16:33:16 -0700
commit2e9bec1154b8342ae6914498edd2e0fb15e36957 (patch)
treef605a39a176afd39c9ffcc18fd71b4c8c74e75a9 /tools/aapt2/ResourceParser.cpp
parent1d008d1d2a73a8b796add4e18924fcc99220a839 (diff)
Add staging-public-group to aapt2
staging-public-group is a tag for putting resources that have been added during platform development, but have not yet been finalized, into a separate resource id namespace. R.java fields of staged resources are non-final, so when the SDK is finalized, applications using the android R.java will automatically use the new finalized resource id without having to recompile. Staged resources can exist either in the same type id as the type's non-staged counterpart or in a separate type id. Multiple staging-public-group tags each with a different type id can exist simultaneously, which allows for multiple versions of the platform to be developed at once. Bug: 183411093 Test: aapt2_tests Change-Id: Ibb6c84c3626751e33c6097f35a03e306bb85616a
Diffstat (limited to 'tools/aapt2/ResourceParser.cpp')
-rw-r--r--tools/aapt2/ResourceParser.cpp112
1 files changed, 65 insertions, 47 deletions
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index a447cef6dbbb..24c60b740bc3 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -42,6 +42,10 @@ using ::android::StringPiece;
using android::idmap2::policy::kPolicyStringToFlag;
namespace aapt {
+namespace {
+constexpr const char* kPublicGroupTag = "public-group";
+constexpr const char* kStagingPublicGroupTag = "staging-public-group";
+} // namespace
constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
@@ -102,6 +106,7 @@ struct ParsedResource {
ResourceId id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
+ bool staged_api = false;
bool allow_new = false;
Maybe<OverlayableItem> overlayable_item;
@@ -122,6 +127,7 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
if (res->visibility_level != Visibility::Level::kUndefined) {
Visibility visibility;
visibility.level = res->visibility_level;
+ visibility.staged_api = res->staged_api;
visibility.source = res->source;
visibility.comment = res->comment;
res_builder.SetVisibility(visibility);
@@ -525,6 +531,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
{"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
{"public", std::mem_fn(&ResourceParser::ParsePublic)},
{"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
+ {"staging-public-group", std::mem_fn(&ResourceParser::ParseStagingPublicGroup)},
{"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
{"style", std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kStyle,
std::placeholders::_2, std::placeholders::_3)},
@@ -653,7 +660,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
const auto bag_iter = elToBagMap.find(resource_type);
if (bag_iter != elToBagMap.end()) {
// Ensure we have a name (unless this is a <public-group> or <overlayable>).
- if (resource_type != "public-group" && resource_type != "overlayable") {
+ if (resource_type != kPublicGroupTag && resource_type != kStagingPublicGroupTag &&
+ resource_type != "overlayable") {
if (!maybe_name) {
diag_->Error(DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
@@ -890,54 +898,45 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out
return true;
}
-bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) {
- if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<public-group> tag not allowed with --visibility flag");
- return false;
- }
-
+template <typename Func>
+bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resource,
+ const char* tag_name, IDiagnostics* diag, Func&& func) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for <public-group> tag");
+ diag->Warn(DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for <" << tag_name
+ << "> tag");
}
Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<public-group> must have a 'type' attribute");
+ diag->Error(DiagMessage(out_resource->source)
+ << "<" << tag_name << "> must have a 'type' attribute");
return false;
}
const ResourceType* parsed_type = ParseResourceType(maybe_type.value());
if (!parsed_type) {
- diag_->Error(DiagMessage(out_resource->source) << "invalid resource type '"
- << maybe_type.value()
- << "' in <public-group>");
+ diag->Error(DiagMessage(out_resource->source)
+ << "invalid resource type '" << maybe_type.value() << "' in <" << tag_name << ">");
return false;
}
- Maybe<StringPiece> maybe_id_str =
- xml::FindNonEmptyAttribute(parser, "first-id");
+ Maybe<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id");
if (!maybe_id_str) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<public-group> must have a 'first-id' attribute");
+ diag->Error(DiagMessage(out_resource->source)
+ << "<" << tag_name << "> must have a 'first-id' attribute");
return false;
}
- Maybe<ResourceId> maybe_id =
- ResourceUtils::ParseResourceId(maybe_id_str.value());
+ Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
if (!maybe_id) {
- diag_->Error(DiagMessage(out_resource->source) << "invalid resource ID '"
- << maybe_id_str.value()
- << "' in <public-group>");
+ diag->Error(DiagMessage(out_resource->source)
+ << "invalid resource ID '" << maybe_id_str.value() << "' in <" << tag_name << ">");
return false;
}
- ResourceId next_id = maybe_id.value();
-
std::string comment;
+ ResourceId next_id = maybe_id.value();
bool error = false;
const size_t depth = parser->depth();
while (xml::XmlPullParser::NextChildNode(parser, depth)) {
@@ -949,53 +948,72 @@ bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const Source item_source = out_resource->source.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "public") {
- Maybe<StringPiece> maybe_name =
- xml::FindNonEmptyAttribute(parser, "name");
+ auto maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(item_source)
- << "<public> must have a 'name' attribute");
+ diag->Error(DiagMessage(item_source) << "<public> must have a 'name' attribute");
error = true;
continue;
}
if (xml::FindNonEmptyAttribute(parser, "id")) {
- diag_->Error(DiagMessage(item_source)
- << "'id' is ignored within <public-group>");
+ diag->Error(DiagMessage(item_source) << "'id' is ignored within <" << tag_name << ">");
error = true;
continue;
}
if (xml::FindNonEmptyAttribute(parser, "type")) {
- diag_->Error(DiagMessage(item_source)
- << "'type' is ignored within <public-group>");
+ diag->Error(DiagMessage(item_source) << "'type' is ignored within <" << tag_name << ">");
error = true;
continue;
}
- ParsedResource child_resource;
- child_resource.name.type = *parsed_type;
- child_resource.name.entry = maybe_name.value().to_string();
- child_resource.id = next_id;
- // NOLINTNEXTLINE(bugprone-use-after-move) move+reset comment
- child_resource.comment = std::move(comment);
- child_resource.source = item_source;
- child_resource.visibility_level = Visibility::Level::kPublic;
- out_resource->child_resources.push_back(std::move(child_resource));
+ ParsedResource& entry_res = out_resource->child_resources.emplace_back(ParsedResource{
+ .name = ResourceName{{}, *parsed_type, maybe_name.value().to_string()},
+ .source = item_source,
+ .id = next_id,
+ .comment = std::move(comment),
+ });
- next_id.id += 1;
+ // Execute group specific code.
+ func(entry_res, next_id);
+ next_id.id++;
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag->Error(DiagMessage(item_source) << ":" << element_name << ">");
error = true;
}
}
return !error;
}
+bool ResourceParser::ParseStagingPublicGroup(xml::XmlPullParser* parser,
+ ParsedResource* out_resource) {
+ return ParseGroupImpl(parser, out_resource, kStagingPublicGroupTag, diag_,
+ [](ParsedResource& parsed_entry, ResourceId id) {
+ parsed_entry.id = id;
+ parsed_entry.staged_api = true;
+ parsed_entry.visibility_level = Visibility::Level::kPublic;
+ });
+}
+
+bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ if (options_.visibility) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "<" << kPublicGroupTag << "> tag not allowed with --visibility flag");
+ return false;
+ }
+
+ return ParseGroupImpl(parser, out_resource, kPublicGroupTag, diag_,
+ [](ParsedResource& parsed_entry, ResourceId id) {
+ parsed_entry.id = id;
+ parsed_entry.visibility_level = Visibility::Level::kPublic;
+ });
+}
+
bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
ParsedResource* out_resource) {
Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");