(
+ 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("\n@attr description");
- attrProcessor.appendComment(comment);
+ attrProcessor->appendComment("
\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(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(
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 =
+ util::make_unique(transform(unmangledName), id);
+
+ // Build the comments and annotations for this entry.
+ AnnotationProcessor* processor = resourceMember->getCommentBuilder();
+
+ // Add the comments from any 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(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 classDef = util::make_unique(
+ 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;
}
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 7e46f8c9043c3..b594a88728f43 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -28,7 +28,7 @@
namespace aapt {
class AnnotationProcessor;
-class ClassDefinitionWriter;
+class ClassDefinition;
struct JavaClassGeneratorOptions {
/*
@@ -70,16 +70,15 @@ public:
const std::string& getError() const;
private:
- bool writeEntriesForClass(ClassDefinitionWriter* outClassDef,
- const StringPiece16& packageNameToGenerate,
- const ResourceTablePackage* package,
- const ResourceTableType* type);
+ bool addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+ const ResourceTablePackage* package,
+ const ResourceTableType* type,
+ ClassDefinition* outTypeClassDef);
- void writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
- AnnotationProcessor* processor,
- const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
- const Styleable* styleable);
+ void addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+ const std::u16string& entryName,
+ const Styleable* styleable,
+ ClassDefinition* outStyleableClassDef);
bool skipSymbol(SymbolState state);
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a9b4c14337fe8..be8955ecdf83b 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -16,7 +16,7 @@
#include "Source.h"
#include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
#include "java/ManifestClassGenerator.h"
#include "util/Maybe.h"
#include "xml/XmlDom.h"
@@ -58,8 +58,8 @@ static Maybe extractJavaIdentifier(IDiagnostics* diag, const Sour
return result;
}
-static bool writeSymbol(IDiagnostics* diag, ClassDefinitionWriter* outClassDef, const Source& source,
- xml::Element* el) {
+static bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
+ ClassDefinition* classDef) {
xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
if (!attr) {
diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
@@ -72,54 +72,53 @@ static bool writeSymbol(IDiagnostics* diag, ClassDefinitionWriter* outClassDef,
return false;
}
- AnnotationProcessor processor;
- processor.appendComment(el->comment);
- outClassDef->addStringMember(result.value(), &processor, attr->value);
+ std::unique_ptr stringMember = util::make_unique(
+ util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
+ stringMember->getCommentBuilder()->appendComment(el->comment);
+
+ classDef->addMember(std::move(stringMember));
return true;
}
-bool ManifestClassGenerator::generate(IDiagnostics* diag, const StringPiece16& package,
- xml::XmlResource* res, std::ostream* out) {
+std::unique_ptr generateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
xml::Element* el = xml::findRootElement(res->root.get());
if (!el) {
- return false;
+ diag->error(DiagMessage(res->file.source) << "no root tag defined");
+ return {};
}
if (el->name != u"manifest" && !el->namespaceUri.empty()) {
diag->error(DiagMessage(res->file.source) << "no root tag defined");
- return false;
+ return {};
}
- *out << "package " << package << ";\n\n"
- << "public final class Manifest {\n";
+ std::unique_ptr permissionClass =
+ util::make_unique("permission", ClassQualifier::Static, false);
+ std::unique_ptr permissionGroupClass =
+ util::make_unique("permission_group", ClassQualifier::Static, false);
bool error = false;
+
std::vector children = el->getChildElements();
-
- ClassDefinitionWriterOptions classOptions;
- classOptions.useFinalQualifier = true;
- classOptions.forceCreationIfEmpty = false;
-
- // First write out permissions.
- ClassDefinitionWriter classDef("permission", classOptions);
for (xml::Element* childEl : children) {
- if (childEl->namespaceUri.empty() && childEl->name == u"permission") {
- error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
+ if (childEl->namespaceUri.empty()) {
+ if (childEl->name == u"permission") {
+ error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
+ } else if (childEl->name == u"permission-group") {
+ error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
+ }
}
}
- classDef.writeToStream(out, " ");
- // Next write out permission groups.
- classDef = ClassDefinitionWriter("permission_group", classOptions);
- for (xml::Element* childEl : children) {
- if (childEl->namespaceUri.empty() && childEl->name == u"permission-group") {
- error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
- }
+ if (error) {
+ return {};
}
- classDef.writeToStream(out, " ");
- *out << "}\n";
- return !error;
+ std::unique_ptr manifestClass =
+ util::make_unique("Manifest", ClassQualifier::None, false);
+ manifestClass->addMember(std::move(permissionClass));
+ manifestClass->addMember(std::move(permissionGroupClass));
+ return manifestClass;
}
} // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 226ed23b85f88..f565289393fb0 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -18,6 +18,7 @@
#define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
#include "Diagnostics.h"
+#include "java/ClassDefinition.h"
#include "util/StringPiece.h"
#include "xml/XmlDom.h"
@@ -25,10 +26,7 @@
namespace aapt {
-struct ManifestClassGenerator {
- bool generate(IDiagnostics* diag, const StringPiece16& package, xml::XmlResource* res,
- std::ostream* out);
-};
+std::unique_ptr generateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
} // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index fc57ae6fd8ffc..a9ec3189ec4f9 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -22,6 +22,23 @@
namespace aapt {
+static ::testing::AssertionResult getManifestClassText(IAaptContext* context, xml::XmlResource* res,
+ std::string* outStr) {
+ std::unique_ptr manifestClass = generateManifestClass(
+ context->getDiagnostics(), res);
+ if (!manifestClass) {
+ return ::testing::AssertionFailure() << "manifestClass == nullptr";
+ }
+
+ std::stringstream out;
+ if (!manifestClass->writeJavaFile(manifestClass.get(), "android", true, &out)) {
+ return ::testing::AssertionFailure() << "failed to write java file";
+ }
+
+ *outStr = out.str();
+ return ::testing::AssertionSuccess();
+}
+
TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
std::unique_ptr context = test::ContextBuilder().build();
std::unique_ptr manifest = test::buildXmlDom(R"EOF(
@@ -32,11 +49,8 @@ TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
)EOF");
- std::stringstream out;
- ManifestClassGenerator generator;
- ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
- std::string actual = out.str();
+ std::string actual;
+ ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
const size_t permissionClassPos = actual.find("public static final class permission {");
const size_t permissionGroupClassPos =
@@ -87,11 +101,8 @@ TEST(ManifestClassGeneratorTest, CommentsAndAnnotationsArePresent) {
)EOF");
- std::stringstream out;
- ManifestClassGenerator generator;
- ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
- std::string actual = out.str();
+ std::string actual;
+ ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
EXPECT_NE(std::string::npos, actual.find(
R"EOF( /**
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index b84074d1cb58f..8c10fbb6e38af 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -762,9 +762,24 @@ public:
return true;
}
+ std::unique_ptr manifestClass = generateManifestClass(
+ mContext->getDiagnostics(), manifestXml);
+
+ if (!manifestClass) {
+ // Something bad happened, but we already logged it, so exit.
+ return false;
+ }
+
+ if (manifestClass->empty()) {
+ // Empty Manifest class, no need to generate it.
+ return true;
+ }
+
+ const std::string packageUtf8 = util::utf16ToUtf8(mContext->getCompilationPackage());
+
std::string outPath = mOptions.generateJavaClassPath.value();
- file::appendPath(&outPath,
- file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
+ file::appendPath(&outPath, file::packageToPath(packageUtf8));
+
if (!file::mkdirs(outPath)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed to create directory '" << outPath << "'");
@@ -780,13 +795,7 @@ public:
return false;
}
- ManifestClassGenerator generator;
- if (!generator.generate(mContext->getDiagnostics(), mContext->getCompilationPackage(),
- manifestXml, &fout)) {
- return false;
- }
-
- if (!fout) {
+ if (!ClassDefinition::writeJavaFile(manifestClass.get(), packageUtf8, true, &fout)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;