Loading tools/aapt2/Android.mk +6 −3 Original line number Original line Diff line number Diff line Loading @@ -45,9 +45,11 @@ sources := \ ConfigDescription.cpp \ ConfigDescription.cpp \ Debug.cpp \ Debug.cpp \ Flags.cpp \ Flags.cpp \ JavaClassGenerator.cpp \ java/AnnotationProcessor.cpp \ java/JavaClassGenerator.cpp \ java/ManifestClassGenerator.cpp \ java/ProguardRules.cpp \ Locale.cpp \ Locale.cpp \ ProguardRules.cpp \ Resource.cpp \ Resource.cpp \ ResourceParser.cpp \ ResourceParser.cpp \ ResourceTable.cpp \ ResourceTable.cpp \ Loading Loading @@ -76,7 +78,8 @@ testSources := \ util/StringPiece_test.cpp \ util/StringPiece_test.cpp \ util/Util_test.cpp \ util/Util_test.cpp \ ConfigDescription_test.cpp \ ConfigDescription_test.cpp \ JavaClassGenerator_test.cpp \ java/JavaClassGenerator_test.cpp \ java/ManifestClassGenerator_test.cpp \ Locale_test.cpp \ Locale_test.cpp \ Resource_test.cpp \ Resource_test.cpp \ ResourceParser_test.cpp \ ResourceParser_test.cpp \ Loading tools/aapt2/Resource.cpp +0 −2 Original line number Original line Diff line number Diff line Loading @@ -36,7 +36,6 @@ StringPiece16 toString(ResourceType type) { case ResourceType::kFraction: return u"fraction"; case ResourceType::kFraction: return u"fraction"; case ResourceType::kId: return u"id"; case ResourceType::kId: return u"id"; case ResourceType::kInteger: return u"integer"; case ResourceType::kInteger: return u"integer"; case ResourceType::kIntegerArray: return u"integer-array"; case ResourceType::kInterpolator: return u"interpolator"; case ResourceType::kInterpolator: return u"interpolator"; case ResourceType::kLayout: return u"layout"; case ResourceType::kLayout: return u"layout"; case ResourceType::kMenu: return u"menu"; case ResourceType::kMenu: return u"menu"; Loading Loading @@ -65,7 +64,6 @@ static const std::map<StringPiece16, ResourceType> sResourceTypeMap { { u"fraction", ResourceType::kFraction }, { u"fraction", ResourceType::kFraction }, { u"id", ResourceType::kId }, { u"id", ResourceType::kId }, { u"integer", ResourceType::kInteger }, { u"integer", ResourceType::kInteger }, { u"integer-array", ResourceType::kIntegerArray }, { u"interpolator", ResourceType::kInterpolator }, { u"interpolator", ResourceType::kInterpolator }, { u"layout", ResourceType::kLayout }, { u"layout", ResourceType::kLayout }, { u"menu", ResourceType::kMenu }, { u"menu", ResourceType::kMenu }, Loading tools/aapt2/Resource.h +0 −1 Original line number Original line Diff line number Diff line Loading @@ -47,7 +47,6 @@ enum class ResourceType { kFraction, kFraction, kId, kId, kInteger, kInteger, kIntegerArray, kInterpolator, kInterpolator, kLayout, kLayout, kMenu, kMenu, Loading tools/aapt2/ResourceParser.cpp +63 −48 Original line number Original line Diff line number Diff line Loading @@ -308,6 +308,9 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { } else if (elementName == u"dimen") { } else if (elementName == u"dimen") { parsedResource.name.type = ResourceType::kDimen; parsedResource.name.type = ResourceType::kDimen; result = parsePrimitive(parser, &parsedResource); result = parsePrimitive(parser, &parsedResource); } else if (elementName == u"fraction") { parsedResource.name.type = ResourceType::kFraction; result = parsePrimitive(parser, &parsedResource); } else if (elementName == u"style") { } else if (elementName == u"style") { parsedResource.name.type = ResourceType::kStyle; parsedResource.name.type = ResourceType::kStyle; result = parseStyle(parser, &parsedResource); result = parseStyle(parser, &parsedResource); Loading @@ -321,7 +324,7 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { parsedResource.name.type = ResourceType::kArray; parsedResource.name.type = ResourceType::kArray; result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING); result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING); } else if (elementName == u"integer-array") { } 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); result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER); } else if (elementName == u"declare-styleable") { } else if (elementName == u"declare-styleable") { parsedResource.name.type = ResourceType::kStyleable; parsedResource.name.type = ResourceType::kStyleable; Loading Loading @@ -464,6 +467,8 @@ bool ResourceParser::parsePrimitive(XmlPullParser* parser, ParsedResource* outRe typeMask |= android::ResTable_map::TYPE_INTEGER; typeMask |= android::ResTable_map::TYPE_INTEGER; break; break; case ResourceType::kFraction: // fallthrough case ResourceType::kDimen: case ResourceType::kDimen: typeMask |= android::ResTable_map::TYPE_DIMENSION typeMask |= android::ResTable_map::TYPE_DIMENSION | android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FLOAT Loading Loading @@ -576,6 +581,12 @@ static uint32_t parseFormatAttribute(const StringPiece16& str) { return mask; 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) { bool ResourceParser::parseAttr(XmlPullParser* parser, ParsedResource* outResource) { outResource->source = mSource.withLine(parser->getLineNumber()); outResource->source = mSource.withLine(parser->getLineNumber()); Loading Loading @@ -613,25 +624,30 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { if (parser->getEvent() == XmlPullParser::Event::kComment) { // Skip comments and text. comment = util::trimWhitespace(parser->getComment()).toString(); continue; } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) { // Skip text. continue; continue; } } const Source itemSource = mSource.withLine(parser->getLineNumber()); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); 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 (elementName == u"enum") { if (typeMask & android::ResTable_map::TYPE_FLAGS) { 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>"); << "can not define an <enum>; already defined a <flag>"); error = true; error = true; continue; continue; } } typeMask |= android::ResTable_map::TYPE_ENUM; typeMask |= android::ResTable_map::TYPE_ENUM; } else if (elementName == u"flag") { } else if (elementName == u"flag") { if (typeMask & android::ResTable_map::TYPE_ENUM) { 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>"); << "can not define a <flag>; already defined an <enum>"); error = true; error = true; continue; continue; Loading @@ -642,21 +658,22 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) { if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) { ParsedResource childResource; ParsedResource childResource; childResource.name = s.value().symbol.name.value(); childResource.name = s.value().symbol.name.value(); childResource.source = mSource.withLine(parser->getLineNumber()); childResource.source = itemSource; childResource.value = util::make_unique<Id>(); childResource.value = util::make_unique<Id>(); outResource->childResources.push_back(std::move(childResource)); 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())); items.push_back(std::move(s.value())); } else { } else { error = true; error = true; } } } else if (elementName == u"skip" || elementName == u"eat-comment") { } else if (!shouldIgnoreElement(elementNamespace, elementName)) { comment = u""; mDiag->error(DiagMessage(itemSource) << ":" << elementName << ">"); } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << ":" << elementName << ">"); error = true; error = true; } } comment = {}; } } if (error) { if (error) { Loading Loading @@ -716,11 +733,10 @@ static Maybe<ResourceName> parseXmlAttributeName(StringPiece16 str) { p++; p++; } } return ResourceName{ package.toString(), ResourceType::kAttr, return ResourceName(package.toString(), ResourceType::kAttr, name.empty() ? str.toString() : name.toString() }; name.empty() ? str.toString() : name.toString()); } } bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) { bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) { const Source source = mSource.withLine(parser->getLineNumber()); const Source source = mSource.withLine(parser->getLineNumber()); Loading Loading @@ -783,7 +799,6 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResour } } bool error = false; bool error = false; std::u16string comment; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { Loading @@ -796,11 +811,7 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResour if (elementNamespace == u"" && elementName == u"item") { if (elementNamespace == u"" && elementName == u"item") { error |= !parseStyleItem(parser, style.get()); error |= !parseStyleItem(parser, style.get()); } else if (elementNamespace.empty() && } else if (!shouldIgnoreElement(elementNamespace, elementName)) { (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << ":" << elementName << ">"); << ":" << elementName << ">"); error = true; error = true; Loading @@ -820,7 +831,6 @@ bool ResourceParser::parseArray(XmlPullParser* parser, ParsedResource* outResour const Source source = mSource.withLine(parser->getLineNumber()); const Source source = mSource.withLine(parser->getLineNumber()); std::unique_ptr<Array> array = util::make_unique<Array>(); std::unique_ptr<Array> array = util::make_unique<Array>(); std::u16string comment; bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { Loading @@ -839,13 +849,10 @@ bool ResourceParser::parseArray(XmlPullParser* parser, ParsedResource* outResour error = true; error = true; continue; continue; } } item->setSource(itemSource); array->items.emplace_back(std::move(item)); array->items.emplace_back(std::move(item)); } else if (elementNamespace.empty() && } else if (!shouldIgnoreElement(elementNamespace, elementName)) { (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "unknown tag <" << elementNamespace << ":" << elementName << ">"); << "unknown tag <" << elementNamespace << ":" << elementName << ">"); error = true; error = true; Loading @@ -864,7 +871,6 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou const Source source = mSource.withLine(parser->getLineNumber()); const Source source = mSource.withLine(parser->getLineNumber()); std::unique_ptr<Plural> plural = util::make_unique<Plural>(); std::unique_ptr<Plural> plural = util::make_unique<Plural>(); std::u16string comment; bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { Loading @@ -873,13 +879,14 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou continue; continue; } } const Source itemSource = mSource.withLine(parser->getLineNumber()); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); const std::u16string& elementName = parser->getElementName(); if (elementNamespace.empty() && elementName == u"item") { if (elementNamespace.empty() && elementName == u"item") { const auto endAttrIter = parser->endAttributes(); const auto endAttrIter = parser->endAttributes(); auto attrIter = parser->findAttribute(u"", u"quantity"); auto attrIter = parser->findAttribute(u"", u"quantity"); if (attrIter == endAttrIter || attrIter->value.empty()) { 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'"); << "'quantity'"); error = true; error = true; continue; continue; Loading @@ -900,7 +907,7 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou } else if (trimmedQuantity == u"other") { } else if (trimmedQuantity == u"other") { index = Plural::Other; index = Plural::Other; } else { } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(itemSource) << "<item> in <plural> has invalid value '" << trimmedQuantity << "<item> in <plural> has invalid value '" << trimmedQuantity << "' for attribute 'quantity'"); << "' for attribute 'quantity'"); error = true; error = true; Loading @@ -908,7 +915,7 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou } } if (plural->values[index]) { if (plural->values[index]) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(itemSource) << "duplicate quantity '" << trimmedQuantity << "'"); << "duplicate quantity '" << trimmedQuantity << "'"); error = true; error = true; continue; continue; Loading @@ -918,11 +925,10 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou kNoRawString))) { kNoRawString))) { error = true; error = true; } } } else if (elementNamespace.empty() && plural->values[index]->setSource(itemSource); (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else if (!shouldIgnoreElement(elementNamespace, elementName)) { } else { mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":" mDiag->error(DiagMessage(source) << "unknown tag <" << elementNamespace << ":" << elementName << ">"); << elementName << ">"); error = true; error = true; } } Loading @@ -944,43 +950,52 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser, ParsedResource bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { if (parser->getEvent() == XmlPullParser::Event::kComment) { // Ignore text and comments. comment = util::trimWhitespace(parser->getComment()).toString(); continue; } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) { // Ignore text. continue; continue; } } const Source itemSource = mSource.withLine(parser->getLineNumber()); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); const std::u16string& elementName = parser->getElementName(); if (elementNamespace.empty() && elementName == u"attr") { if (elementNamespace.empty() && elementName == u"attr") { const auto endAttrIter = parser->endAttributes(); const auto endAttrIter = parser->endAttributes(); auto attrIter = parser->findAttribute(u"", u"name"); auto attrIter = parser->findAttribute(u"", u"name"); if (attrIter == endAttrIter || attrIter->value.empty()) { 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; error = true; continue; continue; } } // Create the ParsedResource that will add the attribute to the table. ParsedResource childResource; ParsedResource childResource; childResource.name = ResourceName({}, ResourceType::kAttr, attrIter->value); 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)) { if (!parseAttrImpl(parser, &childResource, true)) { error = true; error = true; continue; continue; } } styleable->entries.push_back(Reference(childResource.name)); // Create the reference to this attribute. outResource->childResources.push_back(std::move(childResource)); Reference childRef(childResource.name); childRef.setComment(childResource.comment); childRef.setSource(itemSource); styleable->entries.push_back(std::move(childRef)); } else if (elementNamespace.empty() && outResource->childResources.push_back(std::move(childResource)); (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else { } else if (!shouldIgnoreElement(elementNamespace, elementName)) { mDiag->error(DiagMessage(source) << "unknown tag <" << elementNamespace << ":" mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":" << elementName << ">"); << elementName << ">"); error = true; error = true; } } comment = {}; } } if (error) { if (error) { Loading tools/aapt2/ResourceParser_test.cpp +28 −0 Original line number Original line Diff line number Diff line Loading @@ -414,6 +414,34 @@ TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) { EXPECT_EQ(value->getComment(), u"One"); EXPECT_EQ(value->getComment(), u"One"); } } TEST_F(ResourceParserTest, ParseNestedComments) { // We only care about declare-styleable and enum/flag attributes because comments // from those end up in R.java std::string input = R"EOF( <declare-styleable name="foo"> <!-- The name of the bar --> <attr name="barName" format="string|reference" /> </declare-styleable> <attr name="foo"> <!-- The very first --> <enum name="one" value="1" /> </attr>)EOF"; ASSERT_TRUE(testParse(input)); Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo"); ASSERT_NE(nullptr, styleable); ASSERT_EQ(1u, styleable->entries.size()); EXPECT_EQ(StringPiece16(u"The name of the bar"), styleable->entries.front().getComment()); Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); ASSERT_NE(nullptr, attr); ASSERT_EQ(1u, attr->symbols.size()); EXPECT_EQ(StringPiece16(u"The very first"), attr->symbols.front().symbol.getComment()); } /* /* * Declaring an ID as public should not require a separate definition * Declaring an ID as public should not require a separate definition * (as an ID has no value). * (as an ID has no value). Loading Loading
tools/aapt2/Android.mk +6 −3 Original line number Original line Diff line number Diff line Loading @@ -45,9 +45,11 @@ sources := \ ConfigDescription.cpp \ ConfigDescription.cpp \ Debug.cpp \ Debug.cpp \ Flags.cpp \ Flags.cpp \ JavaClassGenerator.cpp \ java/AnnotationProcessor.cpp \ java/JavaClassGenerator.cpp \ java/ManifestClassGenerator.cpp \ java/ProguardRules.cpp \ Locale.cpp \ Locale.cpp \ ProguardRules.cpp \ Resource.cpp \ Resource.cpp \ ResourceParser.cpp \ ResourceParser.cpp \ ResourceTable.cpp \ ResourceTable.cpp \ Loading Loading @@ -76,7 +78,8 @@ testSources := \ util/StringPiece_test.cpp \ util/StringPiece_test.cpp \ util/Util_test.cpp \ util/Util_test.cpp \ ConfigDescription_test.cpp \ ConfigDescription_test.cpp \ JavaClassGenerator_test.cpp \ java/JavaClassGenerator_test.cpp \ java/ManifestClassGenerator_test.cpp \ Locale_test.cpp \ Locale_test.cpp \ Resource_test.cpp \ Resource_test.cpp \ ResourceParser_test.cpp \ ResourceParser_test.cpp \ Loading
tools/aapt2/Resource.cpp +0 −2 Original line number Original line Diff line number Diff line Loading @@ -36,7 +36,6 @@ StringPiece16 toString(ResourceType type) { case ResourceType::kFraction: return u"fraction"; case ResourceType::kFraction: return u"fraction"; case ResourceType::kId: return u"id"; case ResourceType::kId: return u"id"; case ResourceType::kInteger: return u"integer"; case ResourceType::kInteger: return u"integer"; case ResourceType::kIntegerArray: return u"integer-array"; case ResourceType::kInterpolator: return u"interpolator"; case ResourceType::kInterpolator: return u"interpolator"; case ResourceType::kLayout: return u"layout"; case ResourceType::kLayout: return u"layout"; case ResourceType::kMenu: return u"menu"; case ResourceType::kMenu: return u"menu"; Loading Loading @@ -65,7 +64,6 @@ static const std::map<StringPiece16, ResourceType> sResourceTypeMap { { u"fraction", ResourceType::kFraction }, { u"fraction", ResourceType::kFraction }, { u"id", ResourceType::kId }, { u"id", ResourceType::kId }, { u"integer", ResourceType::kInteger }, { u"integer", ResourceType::kInteger }, { u"integer-array", ResourceType::kIntegerArray }, { u"interpolator", ResourceType::kInterpolator }, { u"interpolator", ResourceType::kInterpolator }, { u"layout", ResourceType::kLayout }, { u"layout", ResourceType::kLayout }, { u"menu", ResourceType::kMenu }, { u"menu", ResourceType::kMenu }, Loading
tools/aapt2/Resource.h +0 −1 Original line number Original line Diff line number Diff line Loading @@ -47,7 +47,6 @@ enum class ResourceType { kFraction, kFraction, kId, kId, kInteger, kInteger, kIntegerArray, kInterpolator, kInterpolator, kLayout, kLayout, kMenu, kMenu, Loading
tools/aapt2/ResourceParser.cpp +63 −48 Original line number Original line Diff line number Diff line Loading @@ -308,6 +308,9 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { } else if (elementName == u"dimen") { } else if (elementName == u"dimen") { parsedResource.name.type = ResourceType::kDimen; parsedResource.name.type = ResourceType::kDimen; result = parsePrimitive(parser, &parsedResource); result = parsePrimitive(parser, &parsedResource); } else if (elementName == u"fraction") { parsedResource.name.type = ResourceType::kFraction; result = parsePrimitive(parser, &parsedResource); } else if (elementName == u"style") { } else if (elementName == u"style") { parsedResource.name.type = ResourceType::kStyle; parsedResource.name.type = ResourceType::kStyle; result = parseStyle(parser, &parsedResource); result = parseStyle(parser, &parsedResource); Loading @@ -321,7 +324,7 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { parsedResource.name.type = ResourceType::kArray; parsedResource.name.type = ResourceType::kArray; result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING); result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING); } else if (elementName == u"integer-array") { } 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); result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER); } else if (elementName == u"declare-styleable") { } else if (elementName == u"declare-styleable") { parsedResource.name.type = ResourceType::kStyleable; parsedResource.name.type = ResourceType::kStyleable; Loading Loading @@ -464,6 +467,8 @@ bool ResourceParser::parsePrimitive(XmlPullParser* parser, ParsedResource* outRe typeMask |= android::ResTable_map::TYPE_INTEGER; typeMask |= android::ResTable_map::TYPE_INTEGER; break; break; case ResourceType::kFraction: // fallthrough case ResourceType::kDimen: case ResourceType::kDimen: typeMask |= android::ResTable_map::TYPE_DIMENSION typeMask |= android::ResTable_map::TYPE_DIMENSION | android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FLOAT Loading Loading @@ -576,6 +581,12 @@ static uint32_t parseFormatAttribute(const StringPiece16& str) { return mask; 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) { bool ResourceParser::parseAttr(XmlPullParser* parser, ParsedResource* outResource) { outResource->source = mSource.withLine(parser->getLineNumber()); outResource->source = mSource.withLine(parser->getLineNumber()); Loading Loading @@ -613,25 +624,30 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { if (parser->getEvent() == XmlPullParser::Event::kComment) { // Skip comments and text. comment = util::trimWhitespace(parser->getComment()).toString(); continue; } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) { // Skip text. continue; continue; } } const Source itemSource = mSource.withLine(parser->getLineNumber()); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); 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 (elementName == u"enum") { if (typeMask & android::ResTable_map::TYPE_FLAGS) { 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>"); << "can not define an <enum>; already defined a <flag>"); error = true; error = true; continue; continue; } } typeMask |= android::ResTable_map::TYPE_ENUM; typeMask |= android::ResTable_map::TYPE_ENUM; } else if (elementName == u"flag") { } else if (elementName == u"flag") { if (typeMask & android::ResTable_map::TYPE_ENUM) { 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>"); << "can not define a <flag>; already defined an <enum>"); error = true; error = true; continue; continue; Loading @@ -642,21 +658,22 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) { if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) { ParsedResource childResource; ParsedResource childResource; childResource.name = s.value().symbol.name.value(); childResource.name = s.value().symbol.name.value(); childResource.source = mSource.withLine(parser->getLineNumber()); childResource.source = itemSource; childResource.value = util::make_unique<Id>(); childResource.value = util::make_unique<Id>(); outResource->childResources.push_back(std::move(childResource)); 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())); items.push_back(std::move(s.value())); } else { } else { error = true; error = true; } } } else if (elementName == u"skip" || elementName == u"eat-comment") { } else if (!shouldIgnoreElement(elementNamespace, elementName)) { comment = u""; mDiag->error(DiagMessage(itemSource) << ":" << elementName << ">"); } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << ":" << elementName << ">"); error = true; error = true; } } comment = {}; } } if (error) { if (error) { Loading Loading @@ -716,11 +733,10 @@ static Maybe<ResourceName> parseXmlAttributeName(StringPiece16 str) { p++; p++; } } return ResourceName{ package.toString(), ResourceType::kAttr, return ResourceName(package.toString(), ResourceType::kAttr, name.empty() ? str.toString() : name.toString() }; name.empty() ? str.toString() : name.toString()); } } bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) { bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) { const Source source = mSource.withLine(parser->getLineNumber()); const Source source = mSource.withLine(parser->getLineNumber()); Loading Loading @@ -783,7 +799,6 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResour } } bool error = false; bool error = false; std::u16string comment; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { Loading @@ -796,11 +811,7 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResour if (elementNamespace == u"" && elementName == u"item") { if (elementNamespace == u"" && elementName == u"item") { error |= !parseStyleItem(parser, style.get()); error |= !parseStyleItem(parser, style.get()); } else if (elementNamespace.empty() && } else if (!shouldIgnoreElement(elementNamespace, elementName)) { (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << ":" << elementName << ">"); << ":" << elementName << ">"); error = true; error = true; Loading @@ -820,7 +831,6 @@ bool ResourceParser::parseArray(XmlPullParser* parser, ParsedResource* outResour const Source source = mSource.withLine(parser->getLineNumber()); const Source source = mSource.withLine(parser->getLineNumber()); std::unique_ptr<Array> array = util::make_unique<Array>(); std::unique_ptr<Array> array = util::make_unique<Array>(); std::u16string comment; bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { Loading @@ -839,13 +849,10 @@ bool ResourceParser::parseArray(XmlPullParser* parser, ParsedResource* outResour error = true; error = true; continue; continue; } } item->setSource(itemSource); array->items.emplace_back(std::move(item)); array->items.emplace_back(std::move(item)); } else if (elementNamespace.empty() && } else if (!shouldIgnoreElement(elementNamespace, elementName)) { (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "unknown tag <" << elementNamespace << ":" << elementName << ">"); << "unknown tag <" << elementNamespace << ":" << elementName << ">"); error = true; error = true; Loading @@ -864,7 +871,6 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou const Source source = mSource.withLine(parser->getLineNumber()); const Source source = mSource.withLine(parser->getLineNumber()); std::unique_ptr<Plural> plural = util::make_unique<Plural>(); std::unique_ptr<Plural> plural = util::make_unique<Plural>(); std::u16string comment; bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { Loading @@ -873,13 +879,14 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou continue; continue; } } const Source itemSource = mSource.withLine(parser->getLineNumber()); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); const std::u16string& elementName = parser->getElementName(); if (elementNamespace.empty() && elementName == u"item") { if (elementNamespace.empty() && elementName == u"item") { const auto endAttrIter = parser->endAttributes(); const auto endAttrIter = parser->endAttributes(); auto attrIter = parser->findAttribute(u"", u"quantity"); auto attrIter = parser->findAttribute(u"", u"quantity"); if (attrIter == endAttrIter || attrIter->value.empty()) { 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'"); << "'quantity'"); error = true; error = true; continue; continue; Loading @@ -900,7 +907,7 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou } else if (trimmedQuantity == u"other") { } else if (trimmedQuantity == u"other") { index = Plural::Other; index = Plural::Other; } else { } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(itemSource) << "<item> in <plural> has invalid value '" << trimmedQuantity << "<item> in <plural> has invalid value '" << trimmedQuantity << "' for attribute 'quantity'"); << "' for attribute 'quantity'"); error = true; error = true; Loading @@ -908,7 +915,7 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou } } if (plural->values[index]) { if (plural->values[index]) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) mDiag->error(DiagMessage(itemSource) << "duplicate quantity '" << trimmedQuantity << "'"); << "duplicate quantity '" << trimmedQuantity << "'"); error = true; error = true; continue; continue; Loading @@ -918,11 +925,10 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResou kNoRawString))) { kNoRawString))) { error = true; error = true; } } } else if (elementNamespace.empty() && plural->values[index]->setSource(itemSource); (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else if (!shouldIgnoreElement(elementNamespace, elementName)) { } else { mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":" mDiag->error(DiagMessage(source) << "unknown tag <" << elementNamespace << ":" << elementName << ">"); << elementName << ">"); error = true; error = true; } } Loading @@ -944,43 +950,52 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser, ParsedResource bool error = false; bool error = false; const size_t depth = parser->getDepth(); const size_t depth = parser->getDepth(); while (XmlPullParser::nextChildNode(parser, depth)) { while (XmlPullParser::nextChildNode(parser, depth)) { if (parser->getEvent() != XmlPullParser::Event::kStartElement) { if (parser->getEvent() == XmlPullParser::Event::kComment) { // Ignore text and comments. comment = util::trimWhitespace(parser->getComment()).toString(); continue; } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) { // Ignore text. continue; continue; } } const Source itemSource = mSource.withLine(parser->getLineNumber()); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); const std::u16string& elementName = parser->getElementName(); if (elementNamespace.empty() && elementName == u"attr") { if (elementNamespace.empty() && elementName == u"attr") { const auto endAttrIter = parser->endAttributes(); const auto endAttrIter = parser->endAttributes(); auto attrIter = parser->findAttribute(u"", u"name"); auto attrIter = parser->findAttribute(u"", u"name"); if (attrIter == endAttrIter || attrIter->value.empty()) { 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; error = true; continue; continue; } } // Create the ParsedResource that will add the attribute to the table. ParsedResource childResource; ParsedResource childResource; childResource.name = ResourceName({}, ResourceType::kAttr, attrIter->value); 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)) { if (!parseAttrImpl(parser, &childResource, true)) { error = true; error = true; continue; continue; } } styleable->entries.push_back(Reference(childResource.name)); // Create the reference to this attribute. outResource->childResources.push_back(std::move(childResource)); Reference childRef(childResource.name); childRef.setComment(childResource.comment); childRef.setSource(itemSource); styleable->entries.push_back(std::move(childRef)); } else if (elementNamespace.empty() && outResource->childResources.push_back(std::move(childResource)); (elementName == u"skip" || elementName == u"eat-comment")) { comment = u""; } else { } else if (!shouldIgnoreElement(elementNamespace, elementName)) { mDiag->error(DiagMessage(source) << "unknown tag <" << elementNamespace << ":" mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":" << elementName << ">"); << elementName << ">"); error = true; error = true; } } comment = {}; } } if (error) { if (error) { Loading
tools/aapt2/ResourceParser_test.cpp +28 −0 Original line number Original line Diff line number Diff line Loading @@ -414,6 +414,34 @@ TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) { EXPECT_EQ(value->getComment(), u"One"); EXPECT_EQ(value->getComment(), u"One"); } } TEST_F(ResourceParserTest, ParseNestedComments) { // We only care about declare-styleable and enum/flag attributes because comments // from those end up in R.java std::string input = R"EOF( <declare-styleable name="foo"> <!-- The name of the bar --> <attr name="barName" format="string|reference" /> </declare-styleable> <attr name="foo"> <!-- The very first --> <enum name="one" value="1" /> </attr>)EOF"; ASSERT_TRUE(testParse(input)); Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo"); ASSERT_NE(nullptr, styleable); ASSERT_EQ(1u, styleable->entries.size()); EXPECT_EQ(StringPiece16(u"The name of the bar"), styleable->entries.front().getComment()); Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); ASSERT_NE(nullptr, attr); ASSERT_EQ(1u, attr->symbols.size()); EXPECT_EQ(StringPiece16(u"The very first"), attr->symbols.front().symbol.getComment()); } /* /* * Declaring an ID as public should not require a separate definition * Declaring an ID as public should not require a separate definition * (as an ID has no value). * (as an ID has no value). Loading