AAPT2: Support generating Manifest.java
This includes comments from AndroidManifest.xml.
Change-Id: I412d9ecb12bad20a49a683d6b3bea4a0be1235ae
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 44710eb..0c7a4d5 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -308,6 +308,9 @@
} else if (elementName == u"dimen") {
parsedResource.name.type = ResourceType::kDimen;
result = parsePrimitive(parser, &parsedResource);
+ } else if (elementName == u"fraction") {
+ parsedResource.name.type = ResourceType::kFraction;
+ result = parsePrimitive(parser, &parsedResource);
} else if (elementName == u"style") {
parsedResource.name.type = ResourceType::kStyle;
result = parseStyle(parser, &parsedResource);
@@ -321,7 +324,7 @@
parsedResource.name.type = ResourceType::kArray;
result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING);
} else if (elementName == u"integer-array") {
- parsedResource.name.type = ResourceType::kIntegerArray;
+ parsedResource.name.type = ResourceType::kArray;
result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER);
} else if (elementName == u"declare-styleable") {
parsedResource.name.type = ResourceType::kStyleable;
@@ -464,6 +467,8 @@
typeMask |= android::ResTable_map::TYPE_INTEGER;
break;
+ case ResourceType::kFraction:
+ // fallthrough
case ResourceType::kDimen:
typeMask |= android::ResTable_map::TYPE_DIMENSION
| android::ResTable_map::TYPE_FLOAT
@@ -576,6 +581,12 @@
return mask;
}
+/**
+ * Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
+ */
+static bool shouldIgnoreElement(const StringPiece16& ns, const StringPiece16& name) {
+ return ns.empty() && (name == u"skip" || name == u"eat-comment");
+}
bool ResourceParser::parseAttr(XmlPullParser* parser, ParsedResource* outResource) {
outResource->source = mSource.withLine(parser->getLineNumber());
@@ -613,25 +624,30 @@
bool error = false;
const size_t depth = parser->getDepth();
while (XmlPullParser::nextChildNode(parser, depth)) {
- if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
- // Skip comments and text.
+ if (parser->getEvent() == XmlPullParser::Event::kComment) {
+ comment = util::trimWhitespace(parser->getComment()).toString();
+ continue;
+ } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+ // Skip text.
continue;
}
+ const Source itemSource = mSource.withLine(parser->getLineNumber());
const std::u16string& elementNamespace = parser->getElementNamespace();
const std::u16string& elementName = parser->getElementName();
- if (elementNamespace == u"" && (elementName == u"flag" || elementName == u"enum")) {
+ if (elementNamespace.empty() && (elementName == u"flag" || elementName == u"enum")) {
if (elementName == u"enum") {
if (typeMask & android::ResTable_map::TYPE_FLAGS) {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+ mDiag->error(DiagMessage(itemSource)
<< "can not define an <enum>; already defined a <flag>");
error = true;
continue;
}
typeMask |= android::ResTable_map::TYPE_ENUM;
+
} else if (elementName == u"flag") {
if (typeMask & android::ResTable_map::TYPE_ENUM) {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+ mDiag->error(DiagMessage(itemSource)
<< "can not define a <flag>; already defined an <enum>");
error = true;
continue;
@@ -642,21 +658,22 @@
if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) {
ParsedResource childResource;
childResource.name = s.value().symbol.name.value();
- childResource.source = mSource.withLine(parser->getLineNumber());
+ childResource.source = itemSource;
childResource.value = util::make_unique<Id>();
outResource->childResources.push_back(std::move(childResource));
+
+ s.value().symbol.setComment(std::move(comment));
+ s.value().symbol.setSource(itemSource);
items.push_back(std::move(s.value()));
} else {
error = true;
}
- } else if (elementName == u"skip" || elementName == u"eat-comment") {
- comment = u"";
-
- } else {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << ":" << elementName << ">");
+ } else if (!shouldIgnoreElement(elementNamespace, elementName)) {
+ mDiag->error(DiagMessage(itemSource) << ":" << elementName << ">");
error = true;
}
+
+ comment = {};
}
if (error) {
@@ -716,11 +733,10 @@
p++;
}
- return ResourceName{ package.toString(), ResourceType::kAttr,
- name.empty() ? str.toString() : name.toString() };
+ return ResourceName(package.toString(), ResourceType::kAttr,
+ name.empty() ? str.toString() : name.toString());
}
-
bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) {
const Source source = mSource.withLine(parser->getLineNumber());
@@ -783,7 +799,6 @@
}
bool error = false;
- std::u16string comment;
const size_t depth = parser->getDepth();
while (XmlPullParser::nextChildNode(parser, depth)) {
if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
@@ -796,11 +811,7 @@
if (elementNamespace == u"" && elementName == u"item") {
error |= !parseStyleItem(parser, style.get());
- } else if (elementNamespace.empty() &&
- (elementName == u"skip" || elementName == u"eat-comment")) {
- comment = u"";
-
- } else {
+ } else if (!shouldIgnoreElement(elementNamespace, elementName)) {
mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
<< ":" << elementName << ">");
error = true;
@@ -820,7 +831,6 @@
const Source source = mSource.withLine(parser->getLineNumber());
std::unique_ptr<Array> array = util::make_unique<Array>();
- std::u16string comment;
bool error = false;
const size_t depth = parser->getDepth();
while (XmlPullParser::nextChildNode(parser, depth)) {
@@ -839,13 +849,10 @@
error = true;
continue;
}
+ item->setSource(itemSource);
array->items.emplace_back(std::move(item));
- } else if (elementNamespace.empty() &&
- (elementName == u"skip" || elementName == u"eat-comment")) {
- comment = u"";
-
- } else {
+ } else if (!shouldIgnoreElement(elementNamespace, elementName)) {
mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
<< "unknown tag <" << elementNamespace << ":" << elementName << ">");
error = true;
@@ -864,7 +871,6 @@
const Source source = mSource.withLine(parser->getLineNumber());
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
- std::u16string comment;
bool error = false;
const size_t depth = parser->getDepth();
while (XmlPullParser::nextChildNode(parser, depth)) {
@@ -873,13 +879,14 @@
continue;
}
+ const Source itemSource = mSource.withLine(parser->getLineNumber());
const std::u16string& elementNamespace = parser->getElementNamespace();
const std::u16string& elementName = parser->getElementName();
if (elementNamespace.empty() && elementName == u"item") {
const auto endAttrIter = parser->endAttributes();
auto attrIter = parser->findAttribute(u"", u"quantity");
if (attrIter == endAttrIter || attrIter->value.empty()) {
- mDiag->error(DiagMessage(source) << "<item> in <plurals> requires attribute "
+ mDiag->error(DiagMessage(itemSource) << "<item> in <plurals> requires attribute "
<< "'quantity'");
error = true;
continue;
@@ -900,7 +907,7 @@
} else if (trimmedQuantity == u"other") {
index = Plural::Other;
} else {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+ mDiag->error(DiagMessage(itemSource)
<< "<item> in <plural> has invalid value '" << trimmedQuantity
<< "' for attribute 'quantity'");
error = true;
@@ -908,7 +915,7 @@
}
if (plural->values[index]) {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+ mDiag->error(DiagMessage(itemSource)
<< "duplicate quantity '" << trimmedQuantity << "'");
error = true;
continue;
@@ -918,11 +925,10 @@
kNoRawString))) {
error = true;
}
- } else if (elementNamespace.empty() &&
- (elementName == u"skip" || elementName == u"eat-comment")) {
- comment = u"";
- } else {
- mDiag->error(DiagMessage(source) << "unknown tag <" << elementNamespace << ":"
+ plural->values[index]->setSource(itemSource);
+
+ } else if (!shouldIgnoreElement(elementNamespace, elementName)) {
+ mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":"
<< elementName << ">");
error = true;
}
@@ -944,43 +950,52 @@
bool error = false;
const size_t depth = parser->getDepth();
while (XmlPullParser::nextChildNode(parser, depth)) {
- if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
- // Ignore text and comments.
+ if (parser->getEvent() == XmlPullParser::Event::kComment) {
+ comment = util::trimWhitespace(parser->getComment()).toString();
+ continue;
+ } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+ // Ignore text.
continue;
}
+ const Source itemSource = mSource.withLine(parser->getLineNumber());
const std::u16string& elementNamespace = parser->getElementNamespace();
const std::u16string& elementName = parser->getElementName();
if (elementNamespace.empty() && elementName == u"attr") {
const auto endAttrIter = parser->endAttributes();
auto attrIter = parser->findAttribute(u"", u"name");
if (attrIter == endAttrIter || attrIter->value.empty()) {
- mDiag->error(DiagMessage(source) << "<attr> tag must have a 'name' attribute");
+ mDiag->error(DiagMessage(itemSource) << "<attr> tag must have a 'name' attribute");
error = true;
continue;
}
+ // Create the ParsedResource that will add the attribute to the table.
ParsedResource childResource;
childResource.name = ResourceName({}, ResourceType::kAttr, attrIter->value);
- childResource.source = mSource.withLine(parser->getLineNumber());
+ childResource.source = itemSource;
+ childResource.comment = std::move(comment);
if (!parseAttrImpl(parser, &childResource, true)) {
error = true;
continue;
}
- styleable->entries.push_back(Reference(childResource.name));
+ // Create the reference to this attribute.
+ Reference childRef(childResource.name);
+ childRef.setComment(childResource.comment);
+ childRef.setSource(itemSource);
+ styleable->entries.push_back(std::move(childRef));
+
outResource->childResources.push_back(std::move(childResource));
- } else if (elementNamespace.empty() &&
- (elementName == u"skip" || elementName == u"eat-comment")) {
- comment = u"";
-
- } else {
- mDiag->error(DiagMessage(source) << "unknown tag <" << elementNamespace << ":"
+ } else if (!shouldIgnoreElement(elementNamespace, elementName)) {
+ mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":"
<< elementName << ">");
error = true;
}
+
+ comment = {};
}
if (error) {