\n"
+ if (!styleable->getComment().empty()) {
+ styleableComment << styleable->getComment() << "\n";
+ } else {
+ styleableComment << "Attributes that can be used with a " << className << ".\n";
+ }
+ styleableComment <<
+ "Includes the following attributes:
\n"
+ "\n"
+ "\n"
"\n"
- "\n"
"| Attribute | Description |
\n";
+
for (const auto& entry : sortedAttributes) {
const ResourceName& attrName = entry.attrRef->name.value();
- styleableComment << "{@link #" << entry.fieldName << " "
- << attrName.package << ":" << attrName.entry
- << "} | |
\n";
+ styleableComment << "";
+ styleableComment << "{@link #"
+ << entry.fieldName << " "
+ << (!attrName.package.empty()
+ ? attrName.package : mContext->getCompilationPackage())
+ << ":" << attrName.entry
+ << "}";
+ styleableComment << " | ";
+
+ styleableComment << "";
+ if (entry.attribute) {
+ styleableComment << entry.attribute->getComment();
+ }
+ styleableComment << " |
\n";
}
styleableComment << "
\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();
+ const StyleableAttr& styleableAttr = sortedAttributes[i];
+ const ResourceName& attrName = styleableAttr.attrRef->name.value();
+
+ StringPiece16 packageName = attrName.package;
+ if (packageName.empty()) {
+ packageName = mContext->getCompilationPackage();
+ }
AnnotationProcessor attrProcessor;
- std::stringstream doclavaComments;
- doclavaComments << "@attr name ";
- if (!attrName.package.empty()) {
- doclavaComments << attrName.package << ":";
+
+ StringPiece16 comment = styleableAttr.attrRef->getComment();
+ if (styleableAttr.attribute && comment.empty()) {
+ comment = styleableAttr.attribute->getComment();
}
- 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(
- "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.
");
+ if (!comment.empty()) {
+ attrProcessor.appendComment("\n@attr description");
+ attrProcessor.appendComment(comment);
} else {
- processor->appendComment("
Must be one of the following constant values.
");
+ std::stringstream defaultComment;
+ defaultComment
+ << "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());
}
- processor->appendComment("
\n\n"
- "\n"
- "\n"
- "| Constant | Value | Description |
\n");
- for (const Attribute::Symbol& symbol : attr->symbols) {
- std::stringstream line;
- line << "| " << symbol.symbol.name.value().entry << " | "
- << "" << std::hex << symbol.value << std::dec << " | "
- << "" << util::trimWhitespace(symbol.symbol.getComment()) << " |
";
- processor->appendComment(line.str());
+ attrProcessor.appendNewLine();
+
+ if (styleableAttr.attribute) {
+ addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get());
+ attrProcessor.appendNewLine();
}
- processor->appendComment("
");
+
+ std::stringstream doclavaName;
+ doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
+ attrProcessor.appendComment(doclavaName.str());
+ outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
}
}
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 023d6d635f8c3..7e46f8c9043c3 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -19,7 +19,7 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
-
+#include "process/IResourceTableConsumer.h"
#include "util/StringPiece.h"
#include
@@ -51,7 +51,8 @@ struct JavaClassGeneratorOptions {
*/
class JavaClassGenerator {
public:
- JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options);
+ JavaClassGenerator(IAaptContext* context, ResourceTable* table,
+ const JavaClassGeneratorOptions& options);
/*
* Writes the R.java file to `out`. Only symbols belonging to `package` are written.
@@ -82,6 +83,7 @@ private:
bool skipSymbol(SymbolState state);
+ IAaptContext* mContext;
ResourceTable* mTable;
JavaClassGeneratorOptions mOptions;
std::string mError;
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 63d38a8981f42..4f041b88efbcb 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -15,11 +15,9 @@
*/
#include "java/JavaClassGenerator.h"
+#include "test/Test.h"
#include "util/Util.h"
-#include "test/Builders.h"
-
-#include
#include
#include
@@ -31,7 +29,11 @@ TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
.addSimple(u"@android:id/class", ResourceId(0x01020000))
.build();
- JavaClassGenerator generator(table.get(), {});
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+ JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
EXPECT_FALSE(generator.generate(u"android", &out));
@@ -48,7 +50,11 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
.build())
.build();
- JavaClassGenerator generator(table.get(), {});
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+ JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
EXPECT_TRUE(generator.generate(u"android", &out));
@@ -72,7 +78,11 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
.addSimple(u"@android:id/com.foo$two", ResourceId(0x01020001))
.build();
- JavaClassGenerator generator(table.get(), {});
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+ JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", u"com.android.internal", &out));
@@ -90,7 +100,11 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
.addSimple(u"@android:^attr-private/one", ResourceId(0x01010000))
.build();
- JavaClassGenerator generator(table.get(), {});
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+ JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", &out));
@@ -110,10 +124,15 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
.setSymbolState(u"@android:id/two", ResourceId(0x01020001), SymbolState::kPrivate)
.build();
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+
JavaClassGeneratorOptions options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
{
- JavaClassGenerator generator(table.get(), options);
+ JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", &out));
std::string output = out.str();
@@ -124,7 +143,7 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
{
- JavaClassGenerator generator(table.get(), options);
+ JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", &out));
std::string output = out.str();
@@ -135,7 +154,7 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
{
- JavaClassGenerator generator(table.get(), options);
+ JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", &out));
std::string output = out.str();
@@ -189,7 +208,11 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
.build())
.build();
- JavaClassGenerator generator(table.get(), {});
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+ JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
EXPECT_TRUE(generator.generate(u"android", &out));
@@ -207,8 +230,11 @@ TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
test::getValue(table.get(), u"@android:id/foo")
->setComment(std::u16string(u"This is a comment\n@deprecated"));
- JavaClassGenerator generator(table.get(), {});
-
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
+ JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", &out));
std::string actual = out.str();
@@ -241,10 +267,13 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent)
std::unique_ptr(styleable.clone(nullptr)))
.build();
+ std::unique_ptr context = test::ContextBuilder()
+ .addSymbolSource(util::make_unique(table.get()))
+ .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+ .build();
JavaClassGeneratorOptions options;
options.useFinal = false;
- JavaClassGenerator generator(table.get(), options);
-
+ JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
ASSERT_TRUE(generator.generate(u"android", &out));
std::string actual = out.str();
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 418a802983c3b..b84074d1cb58f 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -744,7 +744,7 @@ public:
return false;
}
- JavaClassGenerator generator(table, javaOptions);
+ JavaClassGenerator generator(mContext, table, javaOptions);
if (!generator.generate(packageNameToGenerate, outPackage, &fout)) {
mContext->getDiagnostics()->error(DiagMessage(outPath) << generator.getError());
return false;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index a8f9bfe4fb322..eaaf06f7e530a 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -51,6 +51,11 @@ const SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
// doesn't support unique_ptr.
std::shared_ptr sharedSymbol = std::shared_ptr(symbol.release());
mCache.put(name, sharedSymbol);
+
+ if (sharedSymbol->id) {
+ // The symbol has an ID, so we can also cache this!
+ mIdCache.put(sharedSymbol->id.value(), sharedSymbol);
+ }
return sharedSymbol.get();
}
}
@@ -76,6 +81,25 @@ const SymbolTable::Symbol* SymbolTable::findById(ResourceId id) {
return nullptr;
}
+const SymbolTable::Symbol* SymbolTable::findByReference(const Reference& ref) {
+ // First try the ID. This is because when we lookup by ID, we only fill in the ID cache.
+ // Looking up by name fills in the name and ID cache. So a cache miss will cause a failed
+ // ID lookup, then a successfull name lookup. Subsequent look ups will hit immediately
+ // because the ID is cached too.
+ //
+ // If we looked up by name first, a cache miss would mean we failed to lookup by name, then
+ // succeeded to lookup by ID. Subsequent lookups will miss then hit.
+ const SymbolTable::Symbol* symbol = nullptr;
+ if (ref.id) {
+ symbol = findById(ref.id.value());
+ }
+
+ if (ref.name && !symbol) {
+ symbol = findByName(ref.name.value());
+ }
+ return symbol;
+}
+
std::unique_ptr ResourceTableSymbolSource::findByName(
const ResourceName& name) {
Maybe result = mTable->findResource(name);
@@ -102,7 +126,7 @@ std::unique_ptr ResourceTableSymbolSource::findByName(
if (configValue) {
// This resource has an Attribute.
if (Attribute* attr = valueCast(configValue->value.get())) {
- symbol->attribute = util::make_unique(*attr);
+ symbol->attribute = std::make_shared(*attr);
} else {
return {};
}
@@ -133,7 +157,7 @@ static std::unique_ptr lookupAttributeInTable(const android
// Check to see if it is an attribute.
for (size_t i = 0; i < (size_t) count; i++) {
if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
- s->attribute = util::make_unique(false);
+ s->attribute = std::make_shared(false);
s->attribute->typeMask = entry[i].map.value.data;
break;
}
@@ -272,4 +296,15 @@ std::unique_ptr AssetManagerSymbolSource::findById(Resource
return {};
}
+std::unique_ptr AssetManagerSymbolSource::findByReference(
+ const Reference& ref) {
+ // AssetManager always prefers IDs.
+ if (ref.id) {
+ return findById(ref.id.value());
+ } else if (ref.name) {
+ return findByName(ref.name.value());
+ }
+ return {};
+}
+
} // namespace aapt
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 8ea1c757fc68f..0a6a4a541a8d1 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -52,7 +52,7 @@ class SymbolTable {
public:
struct Symbol {
Maybe id;
- std::unique_ptr attribute;
+ std::shared_ptr attribute;
bool isPublic;
};
@@ -69,6 +69,12 @@ public:
const Symbol* findByName(const ResourceName& name);
const Symbol* findById(ResourceId id);
+ /**
+ * Let's the ISymbolSource decide whether looking up by name or ID is faster, if both
+ * are available.
+ */
+ const Symbol* findByReference(const Reference& ref);
+
private:
std::vector> mSources;
@@ -90,6 +96,18 @@ public:
virtual std::unique_ptr findByName(const ResourceName& name) = 0;
virtual std::unique_ptr findById(ResourceId id) = 0;
+
+ /**
+ * Default implementation tries the name if it exists, else the ID.
+ */
+ virtual std::unique_ptr findByReference(const Reference& ref) {
+ if (ref.name) {
+ return findByName(ref.name.value());
+ } else if (ref.id) {
+ return findById(ref.id.value());
+ }
+ return {};
+ }
};
/**
@@ -122,6 +140,7 @@ public:
std::unique_ptr findByName(const ResourceName& name) override;
std::unique_ptr findById(ResourceId id) override;
+ std::unique_ptr findByReference(const Reference& ref) override;
private:
android::AssetManager mAssets;