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

This commit is contained in:
Adam Lesinski
2016-03-11 09:16:43 +00:00
committed by Android (Google) Code Review
10 changed files with 286 additions and 114 deletions

View File

@@ -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();

View File

@@ -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>

View File

@@ -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();

View File

@@ -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.
*/

View File

@@ -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;
styleableComment << "Attributes that can be used with a " << className << ".\n";
styleableComment << "<table>\n"
if (!styleable->getComment().empty()) {
styleableComment << styleable->getComment() << "\n";
} else {
styleableComment << "Attributes that can be used with a " << className << ".\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();
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(
"<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>");
if (!comment.empty()) {
attrProcessor.appendComment("<p>\n@attr description");
attrProcessor.appendComment(comment);
} else {
processor->appendComment("<p>Must be one of the following constant values.</p>");
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());
}
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());
attrProcessor.appendNewLine();
if (styleableAttr.attribute) {
addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get());
attrProcessor.appendNewLine();
}
processor->appendComment("</table>");
std::stringstream doclavaName;
doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
attrProcessor.appendComment(doclavaName.str());
outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
}
}

View File

@@ -19,7 +19,7 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "process/IResourceTableConsumer.h"
#include "util/StringPiece.h"
#include <ostream>
@@ -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;

View File

@@ -15,11 +15,9 @@
*/
#include "java/JavaClassGenerator.h"
#include "test/Test.h"
#include "util/Util.h"
#include "test/Builders.h"
#include <gtest/gtest.h>
#include <sstream>
#include <string>
@@ -31,7 +29,11 @@ TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
.addSimple(u"@android:id/class", ResourceId(0x01020000))
.build();
JavaClassGenerator generator(table.get(), {});
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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<Id>(table.get(), u"@android:id/foo")
->setComment(std::u16string(u"This is a comment\n@deprecated"));
JavaClassGenerator generator(table.get(), {});
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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>(styleable.clone(nullptr)))
.build();
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.addSymbolSource(util::make_unique<ResourceTableSymbolSource>(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();

View File

@@ -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;

View File

@@ -51,6 +51,11 @@ const SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
// doesn't support unique_ptr.
std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(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<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
const ResourceName& name) {
Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
@@ -102,7 +126,7 @@ std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
if (configValue) {
// This resource has an Attribute.
if (Attribute* attr = valueCast<Attribute>(configValue->value.get())) {
symbol->attribute = util::make_unique<Attribute>(*attr);
symbol->attribute = std::make_shared<Attribute>(*attr);
} else {
return {};
}
@@ -133,7 +157,7 @@ static std::unique_ptr<SymbolTable::Symbol> 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<Attribute>(false);
s->attribute = std::make_shared<Attribute>(false);
s->attribute->typeMask = entry[i].map.value.data;
break;
}
@@ -272,4 +296,15 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(Resource
return {};
}
std::unique_ptr<SymbolTable::Symbol> 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

View File

@@ -52,7 +52,7 @@ class SymbolTable {
public:
struct Symbol {
Maybe<ResourceId> id;
std::unique_ptr<Attribute> attribute;
std::shared_ptr<Attribute> 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<std::unique_ptr<ISymbolSource>> mSources;
@@ -90,6 +96,18 @@ public:
virtual std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) = 0;
virtual std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) = 0;
/**
* Default implementation tries the name if it exists, else the ID.
*/
virtual std::unique_ptr<SymbolTable::Symbol> 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<SymbolTable::Symbol> findByName(const ResourceName& name) override;
std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override;
std::unique_ptr<SymbolTable::Symbol> findByReference(const Reference& ref) override;
private:
android::AssetManager mAssets;