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

Commit 3b4cd940 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

AAPT2: Add support for comments in R.java

Change-Id: Iaa5f3b75bf7de9dbf458fa5c452f7312989f4c4f
parent 104e028c
Loading
Loading
Loading
Loading
+28 −24
Original line number Diff line number Diff line
@@ -132,6 +132,32 @@ struct Public_header {
    uint32_t count;
};

/**
 * A structure representing source data for a resource entry.
 * Appears after an android::ResTable_entry or android::ResTable_map_entry.
 *
 * TODO(adamlesinski): This causes some issues when runtime code checks
 * the size of an android::ResTable_entry. It assumes it is an
 * android::ResTable_map_entry if the size is bigger than an android::ResTable_entry
 * which may not be true if this structure is present.
 */
struct ResTable_entry_source {
    /**
     * File path reference.
     */
    android::ResStringPool_ref path;

    /**
     * Line number this resource was defined on.
     */
    uint32_t line;

    /**
     * Comment string reference.
     */
    android::ResStringPool_ref comment;
};

struct Public_entry {
    uint16_t entryId;

@@ -143,8 +169,7 @@ struct Public_entry {

    uint16_t state;
    android::ResStringPool_ref key;
    android::ResStringPool_ref source;
    uint32_t sourceLine;
    ResTable_entry_source source;
};

/**
@@ -173,28 +198,7 @@ struct SymbolTable_entry {
     * The index into the string pool where the name of this
     * symbol exists.
     */
    uint32_t stringIndex;
};

/**
 * A structure representing the source of a resourc entry.
 * Appears after an android::ResTable_entry or android::ResTable_map_entry.
 *
 * TODO(adamlesinski): This causes some issues when runtime code checks
 * the size of an android::ResTable_entry. It assumes it is an
 * android::ResTable_map_entry if the size is bigger than an android::ResTable_entry
 * which may not be true if this structure is present.
 */
struct ResTable_entry_source {
    /**
     * Index into the source string pool.
     */
    uint32_t pathIndex;

    /**
     * Line number this resource was defined on.
     */
    uint32_t line;
    android::ResStringPool_ref name;
};

/**
+18 −5
Original line number Diff line number Diff line
@@ -54,9 +54,16 @@ static void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) {
struct FlatEntry {
    ResourceEntry* entry;
    Value* value;

    // The entry string pool index to the entry's name.
    uint32_t entryKey;

    // The source string pool index to the source file path.
    uint32_t sourcePathKey;
    uint32_t sourceLine;

    // The source string pool index to the comment.
    uint32_t commentKey;
};

class SymbolWriter {
@@ -318,8 +325,9 @@ private:
        if (mOptions.useExtendedChunks) {
            // Write the extra source block. This will be ignored by the Android runtime.
            ResTable_entry_source* sourceBlock = buffer->nextBlock<ResTable_entry_source>();
            sourceBlock->pathIndex = util::hostToDevice32(entry->sourcePathKey);
            sourceBlock->path.index = util::hostToDevice32(entry->sourcePathKey);
            sourceBlock->line = util::hostToDevice32(entry->sourceLine);
            sourceBlock->comment.index = util::hostToDevice32(entry->commentKey);
            outEntry->size += sizeof(*sourceBlock);
        }

@@ -486,12 +494,14 @@ private:
                publicEntry->entryId = util::hostToDevice32(entry->id.value());
                publicEntry->key.index = util::hostToDevice32(mKeyPool.makeRef(
                        entry->name).getIndex());
                publicEntry->source.index = util::hostToDevice32(mSourcePool->makeRef(
                publicEntry->source.path.index = util::hostToDevice32(mSourcePool->makeRef(
                        util::utf8ToUtf16(entry->symbolStatus.source.path)).getIndex());
                if (entry->symbolStatus.source.line) {
                    publicEntry->sourceLine = util::hostToDevice32(
                    publicEntry->source.line = util::hostToDevice32(
                            entry->symbolStatus.source.line.value());
                }
                publicEntry->source.comment.index = util::hostToDevice32(mSourcePool->makeRef(
                        entry->symbolStatus.comment).getIndex());

                switch (entry->symbolStatus.state) {
                case SymbolState::kPrivate:
@@ -565,13 +575,16 @@ private:
                        lineNumber = value->getSource().line.value();
                    }

                    const StringPool::Ref commentRef = mSourcePool->makeRef(value->getComment());

                    configToEntryListMap[configValue.config]
                            .push_back(FlatEntry{
                                    entry,
                                    value,
                                    keyIndex,
                                    (uint32_t) sourceRef.getIndex(),
                                    lineNumber });
                                    lineNumber,
                                    (uint32_t) commentRef.getIndex() });
                }
            }

@@ -680,7 +693,7 @@ bool TableFlattener::consume(IAaptContext* context, ResourceTable* table) {
    // Update the offsets to their final values.
    if (symbolEntryData) {
        for (SymbolWriter::Entry& entry : symbolOffsets) {
            symbolEntryData->stringIndex = util::hostToDevice32(entry.name.getIndex());
            symbolEntryData->name.index = util::hostToDevice32(entry.name.getIndex());

            // The symbols were all calculated with the packageBuffer offset. We need to
            // add the beginning of the output buffer.
+19 −11
Original line number Diff line number Diff line
@@ -21,16 +21,10 @@

namespace aapt {

void AnnotationProcessor::appendCommentLine(const StringPiece16& line) {
void AnnotationProcessor::appendCommentLine(const std::string& comment) {
    static const std::string sDeprecated = "@deprecated";
    static const std::string sSystemApi = "@SystemApi";

    if (line.empty()) {
        return;
    }

    std::string comment = util::utf16ToUtf8(line);

    if (comment.find(sDeprecated) != std::string::npos && !mDeprecated) {
        mDeprecated = true;
        if (!mAnnotations.empty()) {
@@ -63,14 +57,28 @@ void AnnotationProcessor::appendCommentLine(const StringPiece16& line) {
void AnnotationProcessor::appendComment(const StringPiece16& comment) {
    // We need to process line by line to clean-up whitespace and append prefixes.
    for (StringPiece16 line : util::tokenize(comment, u'\n')) {
        appendCommentLine(util::trimWhitespace(line));
        line = util::trimWhitespace(line);
        if (!line.empty()) {
            appendCommentLine(util::utf16ToUtf8(line));
        }
    }
}

void AnnotationProcessor::appendComment(const StringPiece& comment) {
    for (StringPiece line : util::tokenize(comment, '\n')) {
        line = util::trimWhitespace(line);
        if (!line.empty()) {
            appendCommentLine(line.toString());
        }
    }
}

std::string AnnotationProcessor::buildComment() {
    if (!mComment.empty()) {
        mComment += "\n";
        mComment += mPrefix;
        mComment += " */";
    }
    return std::move(mComment);
}

+2 −1
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ public:
     * we need to collect all the comments.
     */
    void appendComment(const StringPiece16& comment);
    void appendComment(const StringPiece& comment);

    /**
     * Finishes the comment and moves it to the caller. Subsequent calls to buildComment() have
@@ -85,7 +86,7 @@ private:
    bool mDeprecated = false;
    bool mSystemApi = false;

    void appendCommentLine(const StringPiece16& line);
    void appendCommentLine(const std::string& line);
};

} // namespace aapt
+114 −7
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include "Resource.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"

#include "java/AnnotationProcessor.h"
#include "java/JavaClassGenerator.h"
#include "util/StringPiece.h"
@@ -141,6 +143,85 @@ void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGen
    }
}

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::generateType(const StringPiece16& packageNameToGenerate,
                                      const ResourceTablePackage* package,
                                      const ResourceTableType* type,
@@ -186,6 +267,32 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate
            generateStyleable(packageNameToGenerate, unmangledName, static_cast<const Styleable*>(
                    entry->values.front().value.get()), out);
        } else {
            AnnotationProcessor processor("    ");
            if (entry->symbolStatus.state != SymbolState::kUndefined) {
                processor.appendComment(entry->symbolStatus.comment);
            }

            for (const auto& configValue : entry->values) {
                processor.appendComment(configValue.value->getComment());
            }

            if (!entry->values.empty()) {
                if (Attribute* attr = valueCast<Attribute>(entry->values.front().value.get())) {
                    // We list out the available values for the given attribute.
                    addAttributeFormatDoc(&processor, attr);
                }
            }

            std::string comment = processor.buildComment();
            if (!comment.empty()) {
                *out << comment << "\n";
            }

            std::string annotations = processor.buildAnnotations();
            if (!annotations.empty()) {
                *out << annotations << "\n";
            }

            *out << "    " << "public static" << finalModifier
                 << " int " << transform(unmangledName) << " = " << id << ";\n";
        }
Loading