From 3b4cd94034ff3e5567a2ba6da35d640ff61db4b9 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Fri, 30 Oct 2015 16:31:42 -0700 Subject: AAPT2: Add support for comments in R.java Change-Id: Iaa5f3b75bf7de9dbf458fa5c452f7312989f4c4f --- tools/aapt2/java/AnnotationProcessor.cpp | 30 ++++--- tools/aapt2/java/AnnotationProcessor.h | 3 +- tools/aapt2/java/JavaClassGenerator.cpp | 121 +++++++++++++++++++++++++-- tools/aapt2/java/JavaClassGenerator_test.cpp | 31 +++++++ 4 files changed, 166 insertions(+), 19 deletions(-) (limited to 'tools/aapt2/java') diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp index 16440bcf8ad7..b36682d98bfd 100644 --- a/tools/aapt2/java/AnnotationProcessor.cpp +++ b/tools/aapt2/java/AnnotationProcessor.cpp @@ -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() { - mComment += "\n"; - mComment += mPrefix; - mComment += " */"; + if (!mComment.empty()) { + mComment += "\n"; + mComment += mPrefix; + mComment += " */"; + } return std::move(mComment); } diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h index b47210939d06..81a6f6e42759 100644 --- a/tools/aapt2/java/AnnotationProcessor.h +++ b/tools/aapt2/java/AnnotationProcessor.h @@ -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 diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index 0175489cf6ea..dfd2ef6f5372 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -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" @@ -109,13 +111,13 @@ void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGen std::sort(sortedAttributes.begin(), sortedAttributes.end()); // First we emit the array containing the IDs of each attribute. - *out << " " + *out << " " << "public static final int[] " << transform(entryName) << " = {"; const size_t attrCount = sortedAttributes.size(); for (size_t i = 0; i < attrCount; i++) { if (i % kAttribsPerLine == 0) { - *out << "\n "; + *out << "\n "; } *out << sortedAttributes[i].first; @@ -123,11 +125,11 @@ void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGen *out << ", "; } } - *out << "\n };\n"; + *out << "\n };\n"; // Now we emit the indices into the array. for (size_t i = 0; i < attrCount; i++) { - *out << " " + *out << " " << "public static" << finalModifier << " int " << transform(entryName); @@ -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( + "

May be a reference to another resource, in the form\n" + "\"@[+][package:]type/name\" or a theme\n" + "attribute in the form\n" + "\"?[package:]type/name\"."); + } + + if (typeMask & android::ResTable_map::TYPE_STRING) { + processor->appendComment( + "

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("

May be an integer value, such as \"100\"."); + } + + if (typeMask & android::ResTable_map::TYPE_BOOLEAN) { + processor->appendComment( + "

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

May be a color value, in the form of \"#rgb\",\n" + "\"#argb\", \"#rrggbb#aarrggbb\"."); + } + + if (typeMask & android::ResTable_map::TYPE_FLOAT) { + processor->appendComment( + "

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

May be a dimension value, which is a floating point number appended with a\n" + "unit such as \"14.5sp\".\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( + "

May be a fractional value, which is a floating point number appended with\n" + "either % or %p, such as \"14.5%\".\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( + "

Must be one or more (separated by '|') of the following " + "constant values.

"); + } else { + processor->appendComment("

Must be one of the following constant values.

"); + } + + processor->appendComment("\n\n" + "\n" + "\n" + "\n"); + for (const Attribute::Symbol& symbol : attr->symbols) { + std::stringstream line; + line << "" + << "" + << ""; + processor->appendComment(line.str()); + } + processor->appendComment("
ConstantValueDescription
" << symbol.symbol.name.value().entry << "" << std::hex << symbol.value << std::dec << "" << util::trimWhitespace(symbol.symbol.getComment()) << "
"); + } +} + bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate, const ResourceTablePackage* package, const ResourceTableType* type, @@ -186,7 +267,33 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate generateStyleable(packageNameToGenerate, unmangledName, static_cast( entry->values.front().value.get()), out); } else { - *out << " " << "public static" << finalModifier + 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(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"; } } @@ -211,11 +318,11 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, } else { typeStr = toString(type->type); } - *out << " public static final class " << typeStr << " {\n"; + *out << " public static final class " << typeStr << " {\n"; if (!generateType(packageNameToGenerate, package.get(), type.get(), out)) { return false; } - *out << " }\n"; + *out << " }\n"; } } diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp index 3625f9c340ed..2dc387bea8b9 100644 --- a/tools/aapt2/java/JavaClassGenerator_test.cpp +++ b/tools/aapt2/java/JavaClassGenerator_test.cpp @@ -198,4 +198,35 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) { EXPECT_NE(std::string::npos, output.find("int foo_com_lib_bar =")); } +TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) { + std::unique_ptr table = test::ResourceTableBuilder() + .setPackageId(u"android", 0x01) + .addSimple(u"@android:id/foo", ResourceId(0x01010000)) + .build(); + test::getValue(table.get(), u"@android:id/foo") + ->setComment(std::u16string(u"This is a comment\n@deprecated")); + + JavaClassGenerator generator(table.get(), {}); + + std::stringstream out; + ASSERT_TRUE(generator.generate(u"android", &out)); + std::string actual = out.str(); + + EXPECT_NE(std::string::npos, actual.find( + R"EOF(/** + * This is a comment + * @deprecated + */ + @Deprecated + public static final int foo = 0x01010000;)EOF")); +} + +TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) { + +} + +TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) { + +} + } // namespace aapt -- cgit v1.2.3-59-g8ed1b