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

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

Merge "AAPT2: Add descriptions of Attributes in Styleables for R.java" into nyc-dev

parents 607c0a0a 7656554f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -81,6 +81,12 @@ struct ParsedResource {

// Recursively adds resources to the ResourceTable.
static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
    StringPiece16 trimmedComment = util::trimWhitespace(res->comment);
    if (trimmedComment.size() != res->comment.size()) {
        // Only if there was a change do we re-assign.
        res->comment = trimmedComment.toString();
    }

    if (res->symbolState) {
        Symbol symbol;
        symbol.state = res->symbolState.value();
+5 −0
Original line number Diff line number Diff line
@@ -15,8 +15,13 @@
-->

<resources>
    <!-- An attribute from StaticLibOne -->
    <attr name="StaticLibOne_attr" format="string" />

    <string name="Foo">Foo</string>
    <string name="Foo" product="tablet">Bar</string>

    <declare-styleable name="Widget">
        <attr name="StaticLibOne_attr" />
    </declare-styleable>
</resources>
+5 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ void AnnotationProcessor::appendCommentLine(const std::string& comment) {
        mComment << "/**";
    }

    mComment << "\n" << " * " << std::move(comment);
    mComment << "\n * " << std::move(comment);
}

void AnnotationProcessor::appendComment(const StringPiece16& comment) {
@@ -60,6 +60,10 @@ void AnnotationProcessor::appendComment(const StringPiece& comment) {
    }
}

void AnnotationProcessor::appendNewLine() {
    mComment << "\n *";
}

void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) {
    if (mHasComments) {
        std::string result = mComment.str();
+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ public:
    void appendComment(const StringPiece16& comment);
    void appendComment(const StringPiece& comment);

    void appendNewLine();

    /**
     * Writes the comments and annotations to the stream, with the given prefix before each line.
     */
+161 −91
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include "java/AnnotationProcessor.h"
#include "java/ClassDefinitionWriter.h"
#include "java/JavaClassGenerator.h"
#include "process/SymbolTable.h"
#include "util/StringPiece.h"

#include <algorithm>
@@ -33,8 +34,9 @@

namespace aapt {

JavaClassGenerator::JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options) :
        mTable(table), mOptions(options) {
JavaClassGenerator::JavaClassGenerator(IAaptContext* context, ResourceTable* table,
                                       const JavaClassGeneratorOptions& options) :
        mContext(context), mTable(table), mOptions(options) {
}

static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) {
@@ -103,6 +105,85 @@ static std::string transformNestedAttr(const ResourceNameRef& attrName,
    return output;
}

static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) {
    const uint32_t typeMask = attr->typeMask;
    if (typeMask & android::ResTable_map::TYPE_REFERENCE) {
        processor->appendComment(
                "<p>May be a reference to another resource, in the form\n"
                        "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
                        "attribute in the form\n"
                        "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
    }

    if (typeMask & android::ResTable_map::TYPE_STRING) {
        processor->appendComment(
                "<p>May be a string value, using '\\\\;' to escape characters such as\n"
                        "'\\\\n' or '\\\\uxxxx' for a unicode character;");
    }

    if (typeMask & android::ResTable_map::TYPE_INTEGER) {
        processor->appendComment("<p>May be an integer value, such as \"<code>100</code>\".");
    }

    if (typeMask & android::ResTable_map::TYPE_BOOLEAN) {
        processor->appendComment(
                "<p>May be a boolean value, such as \"<code>true</code>\" or\n"
                        "\"<code>false</code>\".");
    }

    if (typeMask & android::ResTable_map::TYPE_COLOR) {
        processor->appendComment(
                "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n"
                        "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
                        "\"<code>#<i>aarrggbb</i></code>\".");
    }

    if (typeMask & android::ResTable_map::TYPE_FLOAT) {
        processor->appendComment(
                "<p>May be a floating point value, such as \"<code>1.2</code>\".");
    }

    if (typeMask & android::ResTable_map::TYPE_DIMENSION) {
        processor->appendComment(
                "<p>May be a dimension value, which is a floating point number appended with a\n"
                        "unit such as \"<code>14.5sp</code>\".\n"
                        "Available units are: px (pixels), dp (density-independent pixels),\n"
                        "sp (scaled pixels based on preferred font size), in (inches), and\n"
                        "mm (millimeters).");
    }

    if (typeMask & android::ResTable_map::TYPE_FRACTION) {
        processor->appendComment(
                "<p>May be a fractional value, which is a floating point number appended with\n"
                        "either % or %p, such as \"<code>14.5%</code>\".\n"
                        "The % suffix always means a percentage of the base size;\n"
                        "the optional %p suffix provides a size relative to some parent container.");
    }

    if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) {
        if (typeMask & android::ResTable_map::TYPE_FLAGS) {
            processor->appendComment(
                    "<p>Must be one or more (separated by '|') of the following "
                            "constant values.</p>");
        } else {
            processor->appendComment("<p>Must be one of the following constant values.</p>");
        }

        processor->appendComment("<table>\n<colgroup align=\"left\" />\n"
                                         "<colgroup align=\"left\" />\n"
                                         "<colgroup align=\"left\" />\n"
                                         "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
        for (const Attribute::Symbol& symbol : attr->symbols) {
            std::stringstream line;
            line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>"
            << "<td>" << std::hex << symbol.value << std::dec << "</td>"
            << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>";
            processor->appendComment(line.str());
        }
        processor->appendComment("</table>");
    }
}

bool JavaClassGenerator::skipSymbol(SymbolState state) {
    switch (mOptions.types) {
    case JavaClassGeneratorOptions::SymbolTypes::kAll:
@@ -117,6 +198,7 @@ bool JavaClassGenerator::skipSymbol(SymbolState state) {

struct StyleableAttr {
    const Reference* attrRef;
    std::shared_ptr<Attribute> attribute;
    std::string fieldName;
};

@@ -148,8 +230,29 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC
        assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
        assert(attr.name && "no name set for Styleable entry");

        sortedAttributes.emplace_back(StyleableAttr{
                &attr, transformNestedAttr(attr.name.value(), className, packageNameToGenerate) });
        StyleableAttr styleableAttr = {};
        styleableAttr.attrRef = &attr;
        styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className,
                                                      packageNameToGenerate);

        Reference mangledReference;
        mangledReference.id = attr.id;
        mangledReference.name = attr.name;
        if (mangledReference.name.value().package.empty()) {
            mangledReference.name.value().package = mContext->getCompilationPackage();
        }

        if (Maybe<ResourceName> mangledName =
                mContext->getNameMangler()->mangleName(mangledReference.name.value())) {
            mangledReference.name = mangledName;
        }

        const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference(
                mangledReference);
        if (symbol) {
            styleableAttr.attribute = symbol->attribute;
        }
        sortedAttributes.push_back(std::move(styleableAttr));
    }
    std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr);

@@ -159,16 +262,34 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC
        // Build the comment string for the Styleable. It includes details about the
        // child attributes.
        std::stringstream styleableComment;
        if (!styleable->getComment().empty()) {
            styleableComment << styleable->getComment() << "\n";
        } else {
            styleableComment << "Attributes that can be used with a " << className << ".\n";
        styleableComment << "<table>\n"
        }
        styleableComment <<
                "<p>Includes the following attributes:</p>\n"
                "<table>\n"
                "<colgroup align=\"left\" />\n"
                "<colgroup align=\"left\" />\n"
                "<colgroup align=\"left\">\n"
                "<tr><th>Attribute</th><th>Description</th></tr>\n";

        for (const auto& entry : sortedAttributes) {
            const ResourceName& attrName = entry.attrRef->name.value();
            styleableComment << "<tr><td><code>{@link #" << entry.fieldName << " "
                    << attrName.package << ":" << attrName.entry
                    << "}</code></td><td></td></tr>\n";
            styleableComment << "<tr><td>";
            styleableComment << "<code>{@link #"
                             << entry.fieldName << " "
                             << (!attrName.package.empty()
                                    ? attrName.package : mContext->getCompilationPackage())
                             << ":" << attrName.entry
                             << "}</code>";
            styleableComment << "</td>";

            styleableComment << "<td>";
            if (entry.attribute) {
                styleableComment << entry.attribute->getComment();
            }
            styleableComment << "</td></tr>\n";
        }
        styleableComment << "</table>\n";
        for (const auto& entry : sortedAttributes) {
@@ -189,96 +310,45 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC

    // Now we emit the indices into the array.
    for (size_t i = 0; i < attrCount; i++) {
        const ResourceName& attrName = sortedAttributes[i].attrRef->name.value();

        AnnotationProcessor attrProcessor;
        std::stringstream doclavaComments;
        doclavaComments << "@attr name ";
        if (!attrName.package.empty()) {
            doclavaComments << attrName.package << ":";
        }
        doclavaComments << attrName.entry;
        attrProcessor.appendComment(doclavaComments.str());
        outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
    }
}

static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) {
    const uint32_t typeMask = attr->typeMask;
    if (typeMask & android::ResTable_map::TYPE_REFERENCE) {
        processor->appendComment(
                "<p>May be a reference to another resource, in the form\n"
                "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
                "attribute in the form\n"
                "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
    }
        const StyleableAttr& styleableAttr = sortedAttributes[i];
        const ResourceName& attrName = styleableAttr.attrRef->name.value();

    if (typeMask & android::ResTable_map::TYPE_STRING) {
        processor->appendComment(
                "<p>May be a string value, using '\\\\;' to escape characters such as\n"
                "'\\\\n' or '\\\\uxxxx' for a unicode character;");
    }

    if (typeMask & android::ResTable_map::TYPE_INTEGER) {
        processor->appendComment("<p>May be an integer value, such as \"<code>100</code>\".");
        StringPiece16 packageName = attrName.package;
        if (packageName.empty()) {
            packageName = mContext->getCompilationPackage();
        }

    if (typeMask & android::ResTable_map::TYPE_BOOLEAN) {
        processor->appendComment(
                "<p>May be a boolean value, such as \"<code>true</code>\" or\n"
                "\"<code>false</code>\".");
    }

    if (typeMask & android::ResTable_map::TYPE_COLOR) {
        processor->appendComment(
                "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n"
                "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
                "\"<code>#<i>aarrggbb</i></code>\".");
    }
        AnnotationProcessor attrProcessor;

    if (typeMask & android::ResTable_map::TYPE_FLOAT) {
        processor->appendComment(
                "<p>May be a floating point value, such as \"<code>1.2</code>\".");
        StringPiece16 comment = styleableAttr.attrRef->getComment();
        if (styleableAttr.attribute && comment.empty()) {
            comment = styleableAttr.attribute->getComment();
        }

    if (typeMask & android::ResTable_map::TYPE_DIMENSION) {
        processor->appendComment(
                "<p>May be a dimension value, which is a floating point number appended with a\n"
                "unit such as \"<code>14.5sp</code>\".\n"
                "Available units are: px (pixels), dp (density-independent pixels),\n"
                "sp (scaled pixels based on preferred font size), in (inches), and\n"
                "mm (millimeters).");
        if (!comment.empty()) {
            attrProcessor.appendComment("<p>\n@attr description");
            attrProcessor.appendComment(comment);
        } else {
            std::stringstream defaultComment;
            defaultComment
                    << "<p>This symbol is the offset where the "
                    << "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n"
                    << "attribute's value can be found in the "
                    << "{@link #" << className << "} array.";
            attrProcessor.appendComment(defaultComment.str());
        }

    if (typeMask & android::ResTable_map::TYPE_FRACTION) {
        processor->appendComment(
                "<p>May be a fractional value, which is a floating point number appended with\n"
                "either % or %p, such as \"<code>14.5%</code>\".\n"
                "The % suffix always means a percentage of the base size;\n"
                "the optional %p suffix provides a size relative to some parent container.");
    }
        attrProcessor.appendNewLine();

    if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) {
        if (typeMask & android::ResTable_map::TYPE_FLAGS) {
            processor->appendComment(
                    "<p>Must be one or more (separated by '|') of the following "
                    "constant values.</p>");
        } else {
            processor->appendComment("<p>Must be one of the following constant values.</p>");
        if (styleableAttr.attribute) {
            addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get());
            attrProcessor.appendNewLine();
        }

        processor->appendComment("<table>\n<colgroup align=\"left\" />\n"
                                 "<colgroup align=\"left\" />\n"
                                 "<colgroup align=\"left\" />\n"
                                 "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
        for (const Attribute::Symbol& symbol : attr->symbols) {
            std::stringstream line;
            line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>"
                 << "<td>" << std::hex << symbol.value << std::dec << "</td>"
                 << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>";
            processor->appendComment(line.str());
        }
        processor->appendComment("</table>");
        std::stringstream doclavaName;
        doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
        attrProcessor.appendComment(doclavaName.str());
        outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
    }
}

Loading