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

Commit 91bbbcf9 authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "Filter products during compile phase"

parents a66682bc 9ba47d81
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -51,12 +51,6 @@ public:
        mMessage << value;
        return *this;
    }
/*
    template <typename T> DiagMessage& operator<<(
            const ::std::function<::std::ostream&(::std::ostream&)>& f) {
        f(mMessage);
        return *this;
    }*/

    DiagMessageActual build() const {
        return DiagMessageActual{ mSource, mMessage.str() };
@@ -72,6 +66,8 @@ struct IDiagnostics {
};

struct StdErrDiagnostics : public IDiagnostics {
    size_t mNumErrors = 0;

    void emit(const DiagMessage& msg, const char* tag) {
        DiagMessageActual actual = msg.build();
        if (!actual.source.path.empty()) {
@@ -81,8 +77,11 @@ struct StdErrDiagnostics : public IDiagnostics {
    }

    void error(const DiagMessage& msg) override {
        if (mNumErrors < 20) {
            emit(msg, "error: ");
        }
        mNumErrors++;
    }

    void warn(const DiagMessage& msg) override {
        emit(msg, "warn: ");
+7 −0
Original line number Diff line number Diff line
@@ -78,6 +78,9 @@ struct ResourceName {
    ResourceType type;
    std::u16string entry;

    ResourceName() = default;
    ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e);

    bool isValid() const;
    bool operator<(const ResourceName& rhs) const;
    bool operator==(const ResourceName& rhs) const;
@@ -226,6 +229,10 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val)
// ResourceName implementation.
//

inline ResourceName::ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e) :
        package(p.toString()), type(t), entry(e.toString()) {
}

inline bool ResourceName::isValid() const {
    return !package.empty() && !entry.empty();
}
+190 −116
Original line number Diff line number Diff line
@@ -49,8 +49,9 @@ static Maybe<StringPiece16> findNonEmptyAttribute(XmlPullParser* parser,
}

ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
                               const ConfigDescription& config) :
        mDiag(diag), mTable(table), mSource(source), mConfig(config) {
                               const ConfigDescription& config,
                               const ResourceParserOptions& options) :
        mDiag(diag), mTable(table), mSource(source), mConfig(config), mOptions(options) {
}

/**
@@ -157,7 +158,62 @@ bool ResourceParser::parse(XmlPullParser* parser) {
    return !error;
}

static bool shouldStripResource(XmlPullParser* parser, const Maybe<std::u16string> productToMatch) {
    assert(parser->getEvent() == XmlPullParser::Event::kStartElement);

    if (Maybe<StringPiece16> maybeProduct = findNonEmptyAttribute(parser, u"product")) {
        if (!productToMatch) {
            if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") {
                // We didn't specify a product and this is not a default product, so skip.
                return true;
            }
        } else {
            if (productToMatch && maybeProduct.value() != productToMatch.value()) {
                // We specified a product, but they don't match.
                return true;
            }
        }
    }
    return false;
}

/**
 * A parsed resource ready to be added to the ResourceTable.
 */
struct ParsedResource {
    ResourceName name;
    Source source;
    ResourceId id;
    bool markPublic = false;
    std::unique_ptr<Value> value;
    std::list<ParsedResource> childResources;
};

// Recursively adds resources to the ResourceTable.
static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
                                IDiagnostics* diag, ParsedResource* res) {
    if (res->markPublic && !table->markPublic(res->name, res->id, res->source, diag)) {
        return false;
    }

    if (!res->value) {
        return true;
    }

    if (!table->addResource(res->name, res->id, config, res->source, std::move(res->value), diag)) {
        return false;
    }

    bool error = false;
    for (ParsedResource& child : res->childResources) {
        error |= !addResourcesToTable(table, config, diag, &child);
    }
    return !error;
}

bool ResourceParser::parseResources(XmlPullParser* parser) {
    std::set<ResourceName> strippedResources;

    bool error = false;
    std::u16string comment;
    const size_t depth = parser->getDepth();
@@ -198,9 +254,8 @@ bool ResourceParser::parseResources(XmlPullParser* parser) {
            continue;
        }

        // Copy because our iterator will go out of scope when
        // we parse more XML.
        std::u16string name = maybeName.value().toString();
        // Check if we should skip this product.
        const bool stripResource = shouldStripResource(parser, mOptions.product);

        if (elementName == u"item") {
            // Items simply have their type encoded in the type attribute.
@@ -214,48 +269,85 @@ bool ResourceParser::parseResources(XmlPullParser* parser) {
            }
        }

        if (elementName == u"id") {
            error |= !mTable->addResource(ResourceNameRef{ {}, ResourceType::kId, name },
                                          {}, mSource.withLine(parser->getLineNumber()),
                                          util::make_unique<Id>(), mDiag);
        ParsedResource parsedResource;
        parsedResource.name.entry = maybeName.value().toString();
        parsedResource.source = mSource.withLine(parser->getLineNumber());

        bool result = true;
        if (elementName == u"id") {
            parsedResource.name.type = ResourceType::kId;
            parsedResource.value = util::make_unique<Id>();
        } else if (elementName == u"string") {
            error |= !parseString(parser, ResourceNameRef{ {}, ResourceType::kString, name });
            parsedResource.name.type = ResourceType::kString;
            result = parseString(parser, &parsedResource);
        } else if (elementName == u"color") {
            error |= !parseColor(parser, ResourceNameRef{ {}, ResourceType::kColor, name });
            parsedResource.name.type = ResourceType::kColor;
            result = parseColor(parser, &parsedResource);
        } else if (elementName == u"drawable") {
            error |= !parseColor(parser, ResourceNameRef{ {}, ResourceType::kDrawable, name });
            parsedResource.name.type = ResourceType::kDrawable;
            result = parseColor(parser, &parsedResource);
        } else if (elementName == u"bool") {
            error |= !parsePrimitive(parser, ResourceNameRef{ {}, ResourceType::kBool, name });
            parsedResource.name.type = ResourceType::kBool;
            result = parsePrimitive(parser, &parsedResource);
        } else if (elementName == u"integer") {
            error |= !parsePrimitive(parser, ResourceNameRef{ {}, ResourceType::kInteger, name });
            parsedResource.name.type = ResourceType::kInteger;
            result = parsePrimitive(parser, &parsedResource);
        } else if (elementName == u"dimen") {
            error |= !parsePrimitive(parser, ResourceNameRef{ {}, ResourceType::kDimen, name });
            parsedResource.name.type = ResourceType::kDimen;
            result = parsePrimitive(parser, &parsedResource);
        } else if (elementName == u"style") {
            error |= !parseStyle(parser, ResourceNameRef{ {}, ResourceType::kStyle, name });
            parsedResource.name.type = ResourceType::kStyle;
            result = parseStyle(parser, &parsedResource);
        } else if (elementName == u"plurals") {
            error |= !parsePlural(parser, ResourceNameRef{ {}, ResourceType::kPlurals, name });
            parsedResource.name.type = ResourceType::kPlurals;
            result = parsePlural(parser, &parsedResource);
        } else if (elementName == u"array") {
            error |= !parseArray(parser, ResourceNameRef{ {}, ResourceType::kArray, name },
                                 android::ResTable_map::TYPE_ANY);
            parsedResource.name.type = ResourceType::kArray;
            result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_ANY);
        } else if (elementName == u"string-array") {
            error |= !parseArray(parser, ResourceNameRef{ {}, ResourceType::kArray, name },
                                 android::ResTable_map::TYPE_STRING);
            parsedResource.name.type = ResourceType::kArray;
            result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING);
        } else if (elementName == u"integer-array") {
            error |= !parseArray(parser, ResourceNameRef{ {}, ResourceType::kArray, name },
                                 android::ResTable_map::TYPE_INTEGER);
        } else if (elementName == u"public") {
            error |= !parsePublic(parser, name);
            parsedResource.name.type = ResourceType::kIntegerArray;
            result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER);
        } else if (elementName == u"declare-styleable") {
            error |= !parseDeclareStyleable(parser,
                                            ResourceNameRef{ {}, ResourceType::kStyleable, name });
            parsedResource.name.type = ResourceType::kStyleable;
            result = parseDeclareStyleable(parser, &parsedResource);
        } else if (elementName == u"attr") {
            error |= !parseAttr(parser, ResourceNameRef{ {}, ResourceType::kAttr, name });
            parsedResource.name.type = ResourceType::kAttr;
            result = parseAttr(parser, &parsedResource);
        } else if (elementName == u"public") {
            result = parsePublic(parser, &parsedResource);
        } else {
            mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber()))
                        << "unknown resource type '" << elementName << "'");
        }

        if (result) {
            // We successfully parsed the resource.

            if (stripResource) {
                // Record that we stripped out this resource name.
                // We will check that at least one variant of this resource was included.
                strippedResources.insert(parsedResource.name);
            } else {
                error |= !addResourcesToTable(mTable, mConfig, mDiag, &parsedResource);
            }
        } else {
            error = true;
        }
    }

    // Check that we included at least one variant of each stripped resource.
    for (const ResourceName& strippedResource : strippedResources) {
        if (!mTable->findResource(strippedResource)) {
            // Failed to find the resource.
            mDiag->error(DiagMessage(mSource) << "resource '" << strippedResource << "' "
                         "was filtered out but no product variant remains");
            error = true;
        }
    }

    return !error;
}

@@ -322,45 +414,35 @@ std::unique_ptr<Item> ResourceParser::parseXml(XmlPullParser* parser, uint32_t t
    return {};
}

bool ResourceParser::parseString(XmlPullParser* parser, const ResourceNameRef& resourceName) {
bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());

    // TODO(adamlesinski): Read "untranslateable" attribute.

    if (Maybe<StringPiece16> maybeProduct = findAttribute(parser, u"product")) {
        if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") {
            // TODO(adamlesinski): Actually match product.
            return true;
        }
    }

    std::unique_ptr<Item> processedItem = parseXml(parser, android::ResTable_map::TYPE_STRING,
                                                   kNoRawString);
    if (!processedItem) {
    outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
    if (!outResource->value) {
        mDiag->error(DiagMessage(source) << "not a valid string");
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(processedItem),
                               mDiag);
    return true;
}

bool ResourceParser::parseColor(XmlPullParser* parser, const ResourceNameRef& resourceName) {
bool ResourceParser::parseColor(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());

    std::unique_ptr<Item> item = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
    if (!item) {
    outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
    if (!outResource->value) {
        mDiag->error(DiagMessage(source) << "invalid color");
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(item),
                               mDiag);
    return true;
}

bool ResourceParser::parsePrimitive(XmlPullParser* parser, const ResourceNameRef& resourceName) {
bool ResourceParser::parsePrimitive(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());

    uint32_t typeMask = 0;
    switch (resourceName.type) {
    switch (outResource->name.type) {
    case ResourceType::kInteger:
        typeMask |= android::ResTable_map::TYPE_INTEGER;
        break;
@@ -380,16 +462,15 @@ bool ResourceParser::parsePrimitive(XmlPullParser* parser, const ResourceNameRef
        break;
    }

    std::unique_ptr<Item> item = parseXml(parser, typeMask, kNoRawString);
    if (!item) {
        mDiag->error(DiagMessage(source) << "invalid " << resourceName.type);
    outResource->value = parseXml(parser, typeMask, kNoRawString);
    if (!outResource->value) {
        mDiag->error(DiagMessage(source) << "invalid " << outResource->name.type);
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(item),
                               mDiag);
    return true;
}

bool ResourceParser::parsePublic(XmlPullParser* parser, const StringPiece16& name) {
bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());

    Maybe<StringPiece16> maybeType = findNonEmptyAttribute(parser, u"type");
@@ -405,27 +486,28 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, const StringPiece16& nam
        return false;
    }

    ResourceNameRef resourceName { {}, *parsedType, name };
    ResourceId resourceId;
    outResource->name.type = *parsedType;

    if (Maybe<StringPiece16> maybeId = findNonEmptyAttribute(parser, u"id")) {
        android::Res_value val;
        bool result = android::ResTable::stringToInt(maybeId.value().data(),
                                                     maybeId.value().size(), &val);
        resourceId.id = val.data;
        ResourceId resourceId(val.data);
        if (!result || !resourceId.isValid()) {
            mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
                         << "' in <public>");
            return false;
        }
        outResource->id = resourceId;
    }

    if (*parsedType == ResourceType::kId) {
        // An ID marked as public is also the definition of an ID.
        mTable->addResource(resourceName, {}, source, util::make_unique<Id>(),
                            mDiag);
        outResource->value = util::make_unique<Id>();
    }
    return mTable->markPublic(resourceName, resourceId, source, mDiag);

    outResource->markPublic = true;
    return true;
}

static uint32_t parseFormatType(const StringPiece16& piece) {
@@ -455,20 +537,13 @@ static uint32_t parseFormatAttribute(const StringPiece16& str) {
    return mask;
}

bool ResourceParser::parseAttr(XmlPullParser* parser, const ResourceNameRef& resourceName) {
    const Source source = mSource.withLine(parser->getLineNumber());
    ResourceName actualName = resourceName.toResourceName();
    std::unique_ptr<Attribute> attr = parseAttrImpl(parser, &actualName, false);
    if (!attr) {
        return false;
    }
    return mTable->addResource(actualName, mConfig, source, std::move(attr),
                               mDiag);

bool ResourceParser::parseAttr(XmlPullParser* parser, ParsedResource* outResource) {
    outResource->source = mSource.withLine(parser->getLineNumber());
    return parseAttrImpl(parser, outResource, false);
}

std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
                                                         ResourceName* resourceName,
                                                         bool weak) {
bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outResource, bool weak) {
    uint32_t typeMask = 0;

    Maybe<StringPiece16> maybeFormat = findAttribute(parser, u"format");
@@ -477,7 +552,7 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
        if (typeMask == 0) {
            mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
                         << "invalid attribute format '" << maybeFormat.value() << "'");
            return {};
            return false;
        }
    }

@@ -486,10 +561,10 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
    // No format attribute is allowed.
    if (weak && !maybeFormat) {
        StringPiece16 package, type, name;
        ResourceUtils::extractResourceName(resourceName->entry, &package, &type, &name);
        ResourceUtils::extractResourceName(outResource->name.entry, &package, &type, &name);
        if (type.empty() && !package.empty()) {
            resourceName->package = package.toString();
            resourceName->entry = name.toString();
            outResource->name.package = package.toString();
            outResource->name.entry = name.toString();
        }
    }

@@ -526,17 +601,15 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
            }

            if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) {
                if (mTable->addResource(s.value().symbol.name.value(), mConfig,
                                        mSource.withLine(parser->getLineNumber()),
                                        util::make_unique<Id>(),
                                        mDiag)) {
                ParsedResource childResource;
                childResource.name = s.value().symbol.name.value();
                childResource.source = mSource.withLine(parser->getLineNumber());
                childResource.value = util::make_unique<Id>();
                outResource->childResources.push_back(std::move(childResource));
                items.push_back(std::move(s.value()));
            } else {
                error = true;
            }
            } else {
                error = true;
            }
        } else if (elementName == u"skip" || elementName == u"eat-comment") {
            comment = u"";

@@ -548,13 +621,14 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
    }

    if (error) {
        return {};
        return false;
    }

    std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak);
    attr->symbols.swap(items);
    attr->typeMask = typeMask ? typeMask : uint32_t(android::ResTable_map::TYPE_ANY);
    return attr;
    outResource->value = std::move(attr);
    return true;
}

Maybe<Attribute::Symbol> ResourceParser::parseEnumOrFlagItem(XmlPullParser* parser,
@@ -637,7 +711,7 @@ bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) {
    return true;
}

bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& resourceName) {
bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());
    std::unique_ptr<Style> style = util::make_unique<Style>();

@@ -660,12 +734,12 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& re

    } else {
        // No parent was specified, so try inferring it from the style name.
        std::u16string styleName = resourceName.entry.toString();
        std::u16string styleName = outResource->name.entry;
        size_t pos = styleName.find_last_of(u'.');
        if (pos != std::string::npos) {
            style->parentInferred = true;
            style->parent = Reference(ResourceName{
                {}, ResourceType::kStyle, styleName.substr(0, pos) });
            style->parent = Reference(
                    ResourceName({}, ResourceType::kStyle, styleName.substr(0, pos)));
        }
    }

@@ -697,11 +771,12 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& re
    if (error) {
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(style),
                               mDiag);

    outResource->value = std::move(style);
    return true;
}

bool ResourceParser::parseArray(XmlPullParser* parser, const ResourceNameRef& resourceName,
bool ResourceParser::parseArray(XmlPullParser* parser, ParsedResource* outResource,
                                uint32_t typeMask) {
    const Source source = mSource.withLine(parser->getLineNumber());
    std::unique_ptr<Array> array = util::make_unique<Array>();
@@ -741,11 +816,12 @@ bool ResourceParser::parseArray(XmlPullParser* parser, const ResourceNameRef& re
    if (error) {
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(array),
                               mDiag);

    outResource->value = std::move(array);
    return true;
}

bool ResourceParser::parsePlural(XmlPullParser* parser, const ResourceNameRef& resourceName) {
bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());
    std::unique_ptr<Plural> plural = util::make_unique<Plural>();

@@ -816,11 +892,12 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, const ResourceNameRef& r
    if (error) {
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(plural), mDiag);

    outResource->value = std::move(plural);
    return true;
}

bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
                                           const ResourceNameRef& resourceName) {
bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser, ParsedResource* outResource) {
    const Source source = mSource.withLine(parser->getLineNumber());
    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();

@@ -844,22 +921,17 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
                continue;
            }

            // Copy because our iterator will be invalidated.
            ResourceName attrResourceName = { {}, ResourceType::kAttr, attrIter->value };
            ParsedResource childResource;
            childResource.name = ResourceName({}, ResourceType::kAttr, attrIter->value);
            childResource.source = mSource.withLine(parser->getLineNumber());

            std::unique_ptr<Attribute> attr = parseAttrImpl(parser, &attrResourceName, true);
            if (!attr) {
            if (!parseAttrImpl(parser, &childResource, true)) {
                error = true;
                continue;
            }

            styleable->entries.emplace_back(attrResourceName);

            // Add the attribute to the resource table. Since it is weakly defined,
            // it won't collide.
            error |= !mTable->addResource(attrResourceName, mConfig,
                                          mSource.withLine(parser->getLineNumber()),
                                          std::move(attr), mDiag);
            styleable->entries.push_back(Reference(childResource.name));
            outResource->childResources.push_back(std::move(childResource));

        } else if (elementNamespace.empty() &&
                (elementName == u"skip" || elementName == u"eat-comment")) {
@@ -875,7 +947,9 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
    if (error) {
        return false;
    }
    return mTable->addResource(resourceName, mConfig, source, std::move(styleable), mDiag);

    outResource->value = std::move(styleable);
    return true;
}

} // namespace aapt
Loading