diff options
Diffstat (limited to 'tools/aapt2/java/JavaClassGenerator.cpp')
-rw-r--r-- | tools/aapt2/java/JavaClassGenerator.cpp | 208 |
1 files changed, 113 insertions, 95 deletions
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index 01330dc6b5a1..2d076c2d5a66 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -21,7 +21,7 @@ #include "ValueVisitor.h" #include "java/AnnotationProcessor.h" -#include "java/ClassDefinitionWriter.h" +#include "java/ClassDefinition.h" #include "java/JavaClassGenerator.h" #include "process/SymbolTable.h" #include "util/StringPiece.h" @@ -39,16 +39,6 @@ JavaClassGenerator::JavaClassGenerator(IAaptContext* context, ResourceTable* tab mContext(context), mTable(table), mOptions(options) { } -static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) { - *out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n" - " *\n" - " * This class was automatically generated by the\n" - " * aapt tool from the resource data it found. It\n" - " * should not be modified by hand.\n" - " */\n\n" - "package " << packageNameToGenerate << ";\n\n"; -} - static const std::set<StringPiece16> sJavaIdentifiers = { u"abstract", u"assert", u"boolean", u"break", u"byte", u"case", u"catch", u"char", u"class", u"const", u"continue", @@ -110,15 +100,15 @@ static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* att 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>\"."); + "\"<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;"); + "'\\\\n' or '\\\\uxxxx' for a unicode character;"); } if (typeMask & android::ResTable_map::TYPE_INTEGER) { @@ -128,14 +118,14 @@ static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* att 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>\"."); + "\"<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>\"."); + "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n" + "\"<code>#<i>aarrggbb</i></code>\"."); } if (typeMask & android::ResTable_map::TYPE_FLOAT) { @@ -146,33 +136,33 @@ static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* att 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)."); + "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."); + "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>"); + "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"); + "<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>" @@ -214,13 +204,15 @@ static bool lessStyleableAttr(const StyleableAttr& lhs, const StyleableAttr& rhs } } -void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef, - AnnotationProcessor* processor, - const StringPiece16& packageNameToGenerate, - const std::u16string& entryName, - const Styleable* styleable) { +void JavaClassGenerator::addMembersToStyleableClass(const StringPiece16& packageNameToGenerate, + const std::u16string& entryName, + const Styleable* styleable, + ClassDefinition* outStyleableClassDef) { const std::string className = transform(entryName); + std::unique_ptr<ResourceArrayMember> styleableArrayDef = + util::make_unique<ResourceArrayMember>(className); + // This must be sorted by resource ID. std::vector<StyleableAttr> sortedAttributes; sortedAttributes.reserve(styleable->entries.size()); @@ -230,6 +222,8 @@ 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"); + // We will need the unmangled, transformed name in the comments and the field, + // so create it once and cache it in this StyleableAttr data structure. StyleableAttr styleableAttr = {}; styleableAttr.attrRef = &attr; styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className, @@ -247,6 +241,8 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC mangledReference.name = mangledName; } + // Look up the symbol so that we can write out in the comments what are possible + // legal values for this attribute. const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference( mangledReference); if (symbol) { @@ -254,10 +250,11 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC } sortedAttributes.push_back(std::move(styleableAttr)); } + + // Sort the attributes by ID. std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr); const size_t attrCount = sortedAttributes.size(); - if (attrCount > 0) { // Build the comment string for the Styleable. It includes details about the // child attributes. @@ -267,6 +264,7 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC } else { styleableComment << "Attributes that can be used with a " << className << ".\n"; } + styleableComment << "<p>Includes the following attributes:</p>\n" "<table>\n" @@ -274,7 +272,7 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC "<colgroup align=\"left\" />\n" "<tr><th>Attribute</th><th>Description</th></tr>\n"; - for (const auto& entry : sortedAttributes) { + for (const StyleableAttr& entry : sortedAttributes) { const ResourceName& attrName = entry.attrRef->name.value(); styleableComment << "<tr><td>"; styleableComment << "<code>{@link #" @@ -292,21 +290,22 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC styleableComment << "</td></tr>\n"; } styleableComment << "</table>\n"; - for (const auto& entry : sortedAttributes) { + + for (const StyleableAttr& entry : sortedAttributes) { styleableComment << "@see #" << entry.fieldName << "\n"; } - processor->appendComment(styleableComment.str()); + + styleableArrayDef->getCommentBuilder()->appendComment(styleableComment.str()); } - auto accessorFunc = [](const StyleableAttr& a) -> ResourceId { - return a.attrRef->id ? a.attrRef->id.value() : ResourceId(0); - }; + // Add the ResourceIds to the array member. + for (const StyleableAttr& styleableAttr : sortedAttributes) { + styleableArrayDef->addElement( + styleableAttr.attrRef->id ? styleableAttr.attrRef->id.value() : ResourceId(0)); + } - // First we emit the array containing the IDs of each attribute. - outClassDef->addArrayMember(className, processor, - sortedAttributes.begin(), - sortedAttributes.end(), - accessorFunc); + // Add the Styleable array to the Styleable class. + outStyleableClassDef->addMember(std::move(styleableArrayDef)); // Now we emit the indices into the array. for (size_t i = 0; i < attrCount; i++) { @@ -318,7 +317,10 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC packageName = mContext->getCompilationPackage(); } - AnnotationProcessor attrProcessor; + std::unique_ptr<IntMember> indexMember = util::make_unique<IntMember>( + sortedAttributes[i].fieldName, i); + + AnnotationProcessor* attrProcessor = indexMember->getCommentBuilder(); StringPiece16 comment = styleableAttr.attrRef->getComment(); if (styleableAttr.attribute && comment.empty()) { @@ -326,8 +328,8 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC } if (!comment.empty()) { - attrProcessor.appendComment("<p>\n@attr description"); - attrProcessor.appendComment(comment); + attrProcessor->appendComment("<p>\n@attr description"); + attrProcessor->appendComment(comment); } else { std::stringstream defaultComment; defaultComment @@ -335,27 +337,29 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC << "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n" << "attribute's value can be found in the " << "{@link #" << className << "} array."; - attrProcessor.appendComment(defaultComment.str()); + attrProcessor->appendComment(defaultComment.str()); } - attrProcessor.appendNewLine(); + attrProcessor->appendNewLine(); if (styleableAttr.attribute) { - addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get()); - attrProcessor.appendNewLine(); + addAttributeFormatDoc(attrProcessor, styleableAttr.attribute.get()); + attrProcessor->appendNewLine(); } std::stringstream doclavaName; doclavaName << "@attr name " << packageName << ":" << attrName.entry;; - attrProcessor.appendComment(doclavaName.str()); - outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i); + attrProcessor->appendComment(doclavaName.str()); + + outStyleableClassDef->addMember(std::move(indexMember)); } } -bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef, - const StringPiece16& packageNameToGenerate, - const ResourceTablePackage* package, - const ResourceTableType* type) { +bool JavaClassGenerator::addMembersToTypeClass(const StringPiece16& packageNameToGenerate, + const ResourceTablePackage* package, + const ResourceTableType* type, + ClassDefinition* outTypeClassDef) { + for (const auto& entry : type->entries) { if (skipSymbol(entry->symbolStatus.state)) { continue; @@ -389,33 +393,41 @@ bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef return false; } - // Build the comments and annotations for this entry. - - 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 this is an Attribute, append the format Javadoc. - 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); - } - } - if (type->type == ResourceType::kStyleable) { assert(!entry->values.empty()); + const Styleable* styleable = static_cast<const Styleable*>( entry->values.front()->value.get()); - writeStyleableEntryForClass(outClassDef, &processor, packageNameToGenerate, - unmangledName, styleable); + + // Comments are handled within this method. + addMembersToStyleableClass(packageNameToGenerate, unmangledName, styleable, + outTypeClassDef); } else { - outClassDef->addResourceMember(transform(unmangledName), &processor, id); + std::unique_ptr<ResourceMember> resourceMember = + util::make_unique<ResourceMember>(transform(unmangledName), id); + + // Build the comments and annotations for this entry. + AnnotationProcessor* processor = resourceMember->getCommentBuilder(); + + // Add the comments from any <public> tags. + if (entry->symbolStatus.state != SymbolState::kUndefined) { + processor->appendComment(entry->symbolStatus.comment); + } + + // Add the comments from all configurations of this entry. + for (const auto& configValue : entry->values) { + processor->appendComment(configValue->value->getComment()); + } + + // If this is an Attribute, append the format Javadoc. + 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); + } + } + + outTypeClassDef->addMember(std::move(resourceMember)); } } return true; @@ -427,9 +439,8 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, st bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, const StringPiece16& outPackageName, std::ostream* out) { - generateHeader(outPackageName, out); - *out << "public final class R {\n"; + ClassDefinition rClass("R", ClassQualifier::None, true); for (const auto& package : mTable->packages) { for (const auto& type : package->types) { @@ -437,13 +448,15 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, continue; } - ClassDefinitionWriterOptions classOptions; - classOptions.useFinalQualifier = mOptions.useFinal; - classOptions.forceCreationIfEmpty = + const bool forceCreationIfEmpty = (mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic); - ClassDefinitionWriter classDef(toString(type->type), classOptions); - bool result = writeEntriesForClass(&classDef, packageNameToGenerate, - package.get(), type.get()); + + std::unique_ptr<ClassDefinition> classDef = util::make_unique<ClassDefinition>( + util::utf16ToUtf8(toString(type->type)), ClassQualifier::Static, + forceCreationIfEmpty); + + bool result = addMembersToTypeClass(packageNameToGenerate, package.get(), type.get(), + classDef.get()); if (!result) { return false; } @@ -452,26 +465,31 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, // Also include private attributes in this same class. ResourceTableType* privType = package->findType(ResourceType::kAttrPrivate); if (privType) { - result = writeEntriesForClass(&classDef, packageNameToGenerate, - package.get(), privType); + result = addMembersToTypeClass(packageNameToGenerate, package.get(), privType, + classDef.get()); if (!result) { return false; } } } - AnnotationProcessor processor; if (type->type == ResourceType::kStyleable && mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) { // When generating a public R class, we don't want Styleable to be part of the API. // It is only emitted for documentation purposes. - processor.appendComment("@doconly"); + AnnotationProcessor* processor = classDef->getCommentBuilder(); + processor->appendComment("@doconly"); } - classDef.writeToStream(out, " ", &processor); + + rClass.addMember(std::move(classDef)); } } - *out << "}\n"; + if (!ClassDefinition::writeJavaFile(&rClass, util::utf16ToUtf8(outPackageName), + mOptions.useFinal, out)) { + return false; + } + out->flush(); return true; } |