AAPT2: Move all file output to FileOutputStream

FileOutputStream is safe to use on Windows, as it opens
files using our compatibility API.

Bug: 68262818
Test: make aapt2_tests
Change-Id: Ib0b27e93edd609b49b1327db7d9867a002198ebb
This commit is contained in:
Adam Lesinski
2017-11-09 11:29:39 -08:00
parent 60303333dc
commit a693c4a32e
20 changed files with 356 additions and 287 deletions

View File

@@ -268,6 +268,11 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id)
return out << res_id.to_string();
}
// For generic code to call 'using std::to_string; to_string(T);'.
inline std::string to_string(const ResourceId& id) {
return id.to_string();
}
//
// ResourceType implementation.
//

View File

@@ -16,7 +16,6 @@
#include <sys/stat.h>
#include <fstream>
#include <queue>
#include <unordered_map>
#include <vector>
@@ -212,6 +211,8 @@ class LinkContext : public IAaptContext {
// This delegate will attempt to masquerade any '@id/' references with ID 0xPPTTEEEE,
// where PP > 7f, as 0x7fPPEEEE. Any potential overlapping is verified and an error occurs if such
// an overlap exists.
//
// See b/37498913.
class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
public:
FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
@@ -652,24 +653,26 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
static bool WriteStableIdMapToPath(IDiagnostics* diag,
const std::unordered_map<ResourceName, ResourceId>& id_map,
const std::string& id_map_path) {
std::ofstream fout(id_map_path, std::ofstream::binary);
if (!fout) {
diag->Error(DiagMessage(id_map_path) << strerror(errno));
io::FileOutputStream fout(id_map_path);
if (fout.HadError()) {
diag->Error(DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
return false;
}
text::Printer printer(&fout);
for (const auto& entry : id_map) {
const ResourceName& name = entry.first;
const ResourceId& id = entry.second;
fout << name << " = " << id << "\n";
printer.Print(name.to_string());
printer.Print(" = ");
printer.Println(id.to_string());
}
fout.Flush();
if (!fout) {
diag->Error(DiagMessage(id_map_path) << "failed writing to file: "
<< android::base::SystemErrorCodeToString(errno));
if (fout.HadError()) {
diag->Error(DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
return false;
}
return true;
}
@@ -985,36 +988,35 @@ class LinkCommand {
file::AppendPath(&out_path, "R.java");
std::ofstream fout(out_path, std::ofstream::binary);
if (!fout) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed writing to '" << out_path
<< "': " << android::base::SystemErrorCodeToString(errno));
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
<< "': " << fout.GetError());
return false;
}
std::unique_ptr<std::ofstream> fout_text;
std::unique_ptr<io::FileOutputStream> fout_text;
if (out_text_symbols_path) {
fout_text =
util::make_unique<std::ofstream>(out_text_symbols_path.value(), std::ofstream::binary);
if (!*fout_text) {
context_->GetDiagnostics()->Error(
DiagMessage() << "failed writing to '" << out_text_symbols_path.value()
<< "': " << android::base::SystemErrorCodeToString(errno));
fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
if (fout_text->HadError()) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed writing to '" << out_text_symbols_path.value()
<< "': " << fout_text->GetError());
return false;
}
}
JavaClassGenerator generator(context_, table, java_options);
if (!generator.Generate(package_name_to_generate, out_package, &fout, fout_text.get())) {
context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.getError());
context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
return false;
}
if (!fout) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed writing to '" << out_path
<< "': " << android::base::SystemErrorCodeToString(errno));
fout.Flush();
if (fout.HadError()) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
<< "': " << fout.GetError());
return false;
}
return true;
@@ -1142,18 +1144,19 @@ class LinkCommand {
file::AppendPath(&out_path, "Manifest.java");
std::ofstream fout(out_path, std::ofstream::binary);
if (!fout) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed writing to '" << out_path
<< "': " << android::base::SystemErrorCodeToString(errno));
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
<< "': " << fout.GetError());
return false;
}
if (!ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout)) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed writing to '" << out_path
<< "': " << android::base::SystemErrorCodeToString(errno));
ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout);
fout.Flush();
if (fout.HadError()) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
<< "': " << fout.GetError());
return false;
}
return true;
@@ -1165,19 +1168,19 @@ class LinkCommand {
}
const std::string& out_path = out.value();
std::ofstream fout(out_path, std::ofstream::binary);
if (!fout) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed to open '" << out_path
<< "': " << android::base::SystemErrorCodeToString(errno));
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
<< "': " << fout.GetError());
return false;
}
proguard::WriteKeepSet(&fout, keep_set);
if (!fout) {
context_->GetDiagnostics()->Error(DiagMessage()
<< "failed writing to '" << out_path
<< "': " << android::base::SystemErrorCodeToString(errno));
proguard::WriteKeepSet(keep_set, &fout);
fout.Flush();
if (fout.HadError()) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
<< "': " << fout.GetError());
return false;
}
return true;

View File

@@ -25,6 +25,12 @@
#include "android-base/macros.h"
#include "android-base/utf8.h"
#if defined(_WIN32)
// This is only needed for O_CLOEXEC.
#include <windows.h>
#define O_CLOEXEC O_NOINHERIT
#endif
using ::android::base::SystemErrorCodeToString;
using ::android::base::unique_fd;
@@ -32,18 +38,20 @@ namespace aapt {
namespace io {
FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
: FileInputStream(::android::base::utf8::open(path.c_str(), O_RDONLY | O_BINARY),
buffer_capacity) {
: buffer_capacity_(buffer_capacity) {
int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode)));
if (fd_ == -1) {
error_ = SystemErrorCodeToString(errno);
} else {
buffer_.reset(new uint8_t[buffer_capacity_]);
}
}
FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
: fd_(fd),
buffer_capacity_(buffer_capacity),
buffer_offset_(0u),
buffer_size_(0u),
total_byte_count_(0u) {
if (fd_ == -1) {
error_ = SystemErrorCodeToString(errno);
: fd_(fd), buffer_capacity_(buffer_capacity) {
if (fd_ < 0) {
error_ = "Bad File Descriptor";
} else {
buffer_.reset(new uint8_t[buffer_capacity_]);
}
@@ -100,9 +108,16 @@ std::string FileInputStream::GetError() const {
return error_;
}
FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
: FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
buffer_capacity) {
FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
: buffer_capacity_(buffer_capacity) {
int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666)));
fd_ = owned_fd_.get();
if (fd_ < 0) {
error_ = SystemErrorCodeToString(errno);
} else {
buffer_.reset(new uint8_t[buffer_capacity_]);
}
}
FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
@@ -111,9 +126,9 @@ FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
}
FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
: fd_(fd), buffer_capacity_(buffer_capacity), buffer_offset_(0u), total_byte_count_(0u) {
if (fd_ == -1) {
error_ = SystemErrorCodeToString(errno);
: fd_(fd), buffer_capacity_(buffer_capacity) {
if (fd_ < 0) {
error_ = "Bad File Descriptor";
} else {
buffer_.reset(new uint8_t[buffer_capacity_]);
}

View File

@@ -22,7 +22,6 @@
#include <memory>
#include <string>
#include "android-base/file.h" // for O_BINARY
#include "android-base/macros.h"
#include "android-base/unique_fd.h"
@@ -55,15 +54,15 @@ class FileInputStream : public InputStream {
android::base::unique_fd fd_;
std::string error_;
std::unique_ptr<uint8_t[]> buffer_;
size_t buffer_capacity_;
size_t buffer_offset_;
size_t buffer_size_;
size_t total_byte_count_;
size_t buffer_capacity_ = 0u;
size_t buffer_offset_ = 0u;
size_t buffer_size_ = 0u;
size_t total_byte_count_ = 0u;
};
class FileOutputStream : public OutputStream {
public:
explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
explicit FileOutputStream(const std::string& path,
size_t buffer_capacity = kDefaultBufferCapacity);
// Does not take ownership of `fd`.
@@ -97,9 +96,9 @@ class FileOutputStream : public OutputStream {
int fd_;
std::string error_;
std::unique_ptr<uint8_t[]> buffer_;
size_t buffer_capacity_;
size_t buffer_offset_;
size_t total_byte_count_;
size_t buffer_capacity_ = 0u;
size_t buffer_offset_ = 0u;
size_t total_byte_count_ = 0u;
};
} // namespace io

View File

@@ -16,6 +16,7 @@
#include "io/FileStream.h"
#include "android-base/file.h"
#include "android-base/macros.h"
#include "android-base/test_utils.h"

View File

@@ -23,6 +23,7 @@
#include "text/Utf8Iterator.h"
#include "util/Util.h"
using ::aapt::text::Printer;
using ::aapt::text::Utf8Iterator;
using ::android::StringPiece;
@@ -109,23 +110,22 @@ void AnnotationProcessor::AppendNewLine() {
}
}
void AnnotationProcessor::WriteToStream(const StringPiece& prefix, std::ostream* out) const {
void AnnotationProcessor::Print(Printer* printer) const {
if (has_comments_) {
std::string result = comment_.str();
for (StringPiece line : util::Tokenize(result, '\n')) {
*out << prefix << line << "\n";
printer->Println(line);
}
*out << prefix << " */"
<< "\n";
printer->Println(" */");
}
if (annotation_bit_mask_ & AnnotationRule::kDeprecated) {
*out << prefix << "@Deprecated\n";
printer->Println("@Deprecated");
}
for (const AnnotationRule& rule : sAnnotationRules) {
if (annotation_bit_mask_ & rule.bit_mask) {
*out << prefix << rule.annotation << "\n";
printer->Println(rule.annotation);
}
}
}

View File

@@ -22,6 +22,8 @@
#include "androidfw/StringPiece.h"
#include "text/Printer.h"
namespace aapt {
// Builds a JavaDoc comment from a set of XML comments.
@@ -61,8 +63,8 @@ class AnnotationProcessor {
void AppendNewLine();
// Writes the comments and annotations to the stream, with the given prefix before each line.
void WriteToStream(const android::StringPiece& prefix, std::ostream* out) const;
// Writes the comments and annotations to the Printer.
void Print(text::Printer* printer) const;
private:
std::stringstream comment_;

View File

@@ -16,8 +16,12 @@
#include "java/AnnotationProcessor.h"
#include "io/StringStream.h"
#include "test/Test.h"
#include "text/Printer.h"
using ::aapt::io::StringOutputStream;
using ::aapt::text::Printer;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::Not;
@@ -33,9 +37,11 @@ TEST(AnnotationProcessorTest, EmitsDeprecated) {
AnnotationProcessor processor;
processor.AppendComment(comment);
std::stringstream result;
processor.WriteToStream("", &result);
std::string annotations = result.str();
std::string annotations;
StringOutputStream out(&annotations);
Printer printer(&out);
processor.Print(&printer);
out.Flush();
EXPECT_THAT(annotations, HasSubstr("@Deprecated"));
}
@@ -44,9 +50,11 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationAndRemovesFromComment) {
AnnotationProcessor processor;
processor.AppendComment("@SystemApi This is a system API");
std::stringstream result;
processor.WriteToStream("", &result);
std::string annotations = result.str();
std::string annotations;
StringOutputStream out(&annotations);
Printer printer(&out);
processor.Print(&printer);
out.Flush();
EXPECT_THAT(annotations, HasSubstr("@android.annotation.SystemApi"));
EXPECT_THAT(annotations, Not(HasSubstr("@SystemApi")));
@@ -57,9 +65,11 @@ TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) {
AnnotationProcessor processor;
processor.AppendComment("@TestApi This is a test API");
std::stringstream result;
processor.WriteToStream("", &result);
std::string annotations = result.str();
std::string annotations;
StringOutputStream out(&annotations);
Printer printer(&out);
processor.Print(&printer);
out.Flush();
EXPECT_THAT(annotations, HasSubstr("@android.annotation.TestApi"));
EXPECT_THAT(annotations, Not(HasSubstr("@TestApi")));

View File

@@ -18,25 +18,27 @@
#include "androidfw/StringPiece.h"
using ::aapt::text::Printer;
using ::android::StringPiece;
namespace aapt {
void ClassMember::WriteToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
processor_.WriteToStream(prefix, out);
void ClassMember::Print(bool /*final*/, Printer* printer) const {
processor_.Print(printer);
}
void MethodDefinition::AppendStatement(const StringPiece& statement) {
statements_.push_back(statement.to_string());
}
void MethodDefinition::WriteToStream(const StringPiece& prefix, bool final,
std::ostream* out) const {
*out << prefix << signature_ << " {\n";
void MethodDefinition::Print(bool final, Printer* printer) const {
printer->Print(signature_).Println(" {");
printer->Indent();
for (const auto& statement : statements_) {
*out << prefix << " " << statement << "\n";
printer->Println(statement);
}
*out << prefix << "}";
printer->Undent();
printer->Print("}");
}
ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
@@ -62,34 +64,32 @@ bool ClassDefinition::empty() const {
return true;
}
void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
std::ostream* out) const {
void ClassDefinition::Print(bool final, Printer* printer) const {
if (empty() && !create_if_empty_) {
return;
}
ClassMember::WriteToStream(prefix, final, out);
ClassMember::Print(final, printer);
*out << prefix << "public ";
printer->Print("public ");
if (qualifier_ == ClassQualifier::kStatic) {
*out << "static ";
printer->Print("static ");
}
*out << "final class " << name_ << " {\n";
std::string new_prefix = prefix.to_string();
new_prefix.append(kIndent);
printer->Print("final class ").Print(name_).Println(" {");
printer->Indent();
for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
// There can be nullptr members when a member is added to the ClassDefinition
// and takes precedence over a previous member with the same name. The overridden member is
// set to nullptr.
if (member != nullptr) {
member->WriteToStream(new_prefix, final, out);
*out << "\n";
member->Print(final, printer);
printer->Println();
}
}
*out << prefix << "}";
printer->Undent();
printer->Print("}");
}
constexpr static const char* sWarningHeader =
@@ -100,11 +100,12 @@ constexpr static const char* sWarningHeader =
" * should not be modified by hand.\n"
" */\n\n";
bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
bool final, std::ostream* out) {
*out << sWarningHeader << "package " << package << ";\n\n";
def->WriteToStream("", final, out);
return bool(*out);
void ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
bool final, io::OutputStream* out) {
Printer printer(out);
printer.Print(sWarningHeader).Print("package ").Print(package).Println(";");
printer.Println();
def->Print(final, &printer);
}
} // namespace aapt

View File

@@ -17,7 +17,6 @@
#ifndef AAPT_JAVA_CLASSDEFINITION_H
#define AAPT_JAVA_CLASSDEFINITION_H
#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -27,6 +26,7 @@
#include "Resource.h"
#include "java/AnnotationProcessor.h"
#include "text/Printer.h"
#include "util/Util.h"
namespace aapt {
@@ -47,11 +47,10 @@ class ClassMember {
virtual const std::string& GetName() const = 0;
// Writes the class member to the out stream. Subclasses should derive this method
// Writes the class member to the Printer. Subclasses should derive this method
// to write their own data. Call this base method from the subclass to write out
// this member's comments/annotations.
virtual void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const;
virtual void Print(bool final, text::Printer* printer) const;
private:
AnnotationProcessor processor_;
@@ -71,11 +70,16 @@ class PrimitiveMember : public ClassMember {
return name_;
}
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
ClassMember::WriteToStream(prefix, final, out);
*out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
<< ";";
void Print(bool final, text::Printer* printer) const override {
using std::to_string;
ClassMember::Print(final, printer);
printer->Print("public static ");
if (final) {
printer->Print("final ");
}
printer->Print("int ").Print(name_).Print("=").Print(to_string(val_)).Print(";");
}
private:
@@ -100,12 +104,14 @@ class PrimitiveMember<std::string> : public ClassMember {
return name_;
}
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
ClassMember::WriteToStream(prefix, final, out);
void Print(bool final, text::Printer* printer) const override {
ClassMember::Print(final, printer);
*out << prefix << "public static " << (final ? "final " : "") << "String "
<< name_ << "=\"" << val_ << "\";";
printer->Print("public static ");
if (final) {
printer->Print("final ");
}
printer->Print("String ").Print(name_).Print("=\"").Print(val_).Print("\";");
}
private:
@@ -136,25 +142,27 @@ class PrimitiveArrayMember : public ClassMember {
return name_;
}
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
ClassMember::WriteToStream(prefix, final, out);
void Print(bool final, text::Printer* printer) const override {
ClassMember::Print(final, printer);
*out << prefix << "public static final int[] " << name_ << "={";
printer->Print("public static final int[] ").Print(name_).Print("={");
printer->Indent();
const auto begin = elements_.begin();
const auto end = elements_.end();
for (auto current = begin; current != end; ++current) {
if (std::distance(begin, current) % kAttribsPerLine == 0) {
*out << "\n" << prefix << kIndent << kIndent;
printer->Println();
}
*out << *current;
printer->Print(to_string(*current));
if (std::distance(current, end) > 1) {
*out << ", ";
printer->Print(", ");
}
}
*out << "\n" << prefix << kIndent << "};";
printer->Println();
printer->Undent();
printer->Print("};");
}
private:
@@ -187,8 +195,7 @@ class MethodDefinition : public ClassMember {
return false;
}
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override;
void Print(bool final, text::Printer* printer) const override;
private:
DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
@@ -201,8 +208,8 @@ enum class ClassQualifier { kNone, kStatic };
class ClassDefinition : public ClassMember {
public:
static bool WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
bool final, std::ostream* out);
static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
bool final, io::OutputStream* out);
ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
: name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
@@ -220,8 +227,7 @@ class ClassDefinition : public ClassMember {
return name_;
}
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override;
void Print(bool final, text::Printer* printer) const override;
private:
DISALLOW_COPY_AND_ASSIGN(ClassDefinition);

View File

@@ -37,8 +37,10 @@
#include "java/ClassDefinition.h"
#include "process/SymbolTable.h"
using android::StringPiece;
using android::base::StringPrintf;
using ::aapt::io::OutputStream;
using ::aapt::text::Printer;
using ::android::StringPiece;
using ::android::base::StringPrintf;
namespace aapt {
@@ -230,7 +232,7 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
const StringPiece& package_name_to_generate,
ClassDefinition* out_class_def,
MethodDefinition* out_rewrite_method,
std::ostream* out_r_txt) {
Printer* r_txt_printer) {
const std::string array_field_name = TransformToFieldName(name.entry);
std::unique_ptr<ResourceArrayMember> array_def =
util::make_unique<ResourceArrayMember>(array_field_name);
@@ -323,8 +325,8 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
array_def->GetCommentBuilder()->AppendComment(styleable_comment.str());
}
if (out_r_txt != nullptr) {
*out_r_txt << "int[] styleable " << array_field_name << " {";
if (r_txt_printer != nullptr) {
r_txt_printer->Print("int[] styleable ").Print(array_field_name).Print(" {");
}
// Add the ResourceIds to the array member.
@@ -332,16 +334,16 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0));
array_def->AddElement(id);
if (out_r_txt != nullptr) {
if (r_txt_printer != nullptr) {
if (i != 0) {
*out_r_txt << ",";
r_txt_printer->Print(",");
}
*out_r_txt << " " << id;
r_txt_printer->Print(" ").Print(id.to_string());
}
}
if (out_r_txt != nullptr) {
*out_r_txt << " }\n";
if (r_txt_printer != nullptr) {
r_txt_printer->Println(" }");
}
// Add the Styleable array to the Styleable class.
@@ -396,9 +398,9 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
attr_processor->AppendComment(
StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data()));
if (out_r_txt != nullptr) {
*out_r_txt << StringPrintf("int styleable %s %d\n", sorted_attributes[i].field_name.data(),
(int)i);
if (r_txt_printer != nullptr) {
r_txt_printer->Println(
StringPrintf("int styleable %s %zd", sorted_attributes[i].field_name.c_str(), i));
}
out_class_def->AddMember(std::move(index_member));
@@ -422,10 +424,12 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id,
const ResourceEntry& entry, ClassDefinition* out_class_def,
MethodDefinition* out_rewrite_method,
std::ostream* out_r_txt) {
text::Printer* r_txt_printer) {
ResourceId real_id = id;
if (context_->GetMinSdkVersion() < SDK_O && name.type == ResourceType::kId &&
id.package_id() > kAppPackageId) {
// Workaround for feature splits using package IDs > 0x7F.
// See b/37498913.
real_id = ResourceId(kAppPackageId, id.package_id(), id.entry_id());
}
@@ -456,8 +460,13 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
out_class_def->AddMember(std::move(resource_member));
if (out_r_txt != nullptr) {
*out_r_txt << "int " << name.type << " " << field_name << " " << real_id << "\n";
if (r_txt_printer != nullptr) {
r_txt_printer->Print("int ")
.Print(to_string(name.type))
.Print(" ")
.Print(field_name)
.Print(" ")
.Println(real_id.to_string());
}
if (out_rewrite_method != nullptr) {
@@ -497,7 +506,7 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
const ResourceTableType& type,
ClassDefinition* out_type_class_def,
MethodDefinition* out_rewrite_method_def,
std::ostream* out_r_txt) {
Printer* r_txt_printer) {
for (const auto& entry : type.entries) {
const Maybe<std::string> unmangled_name =
UnmangleResource(package.name, package_name_to_generate, *entry);
@@ -532,18 +541,18 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
static_cast<const Styleable*>(entry->values.front()->value.get());
ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def,
out_rewrite_method_def, out_r_txt);
out_rewrite_method_def, r_txt_printer);
} else {
ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def,
out_r_txt);
r_txt_printer);
}
}
return true;
}
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, std::ostream* out,
std::ostream* out_r_txt) {
return Generate(package_name_to_generate, package_name_to_generate, out);
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, OutputStream* out,
OutputStream* out_r_txt) {
return Generate(package_name_to_generate, package_name_to_generate, out, out_r_txt);
}
static void AppendJavaDocAnnotations(const std::vector<std::string>& annotations,
@@ -556,11 +565,16 @@ static void AppendJavaDocAnnotations(const std::vector<std::string>& annotations
}
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
const StringPiece& out_package_name, std::ostream* out,
std::ostream* out_r_txt) {
const StringPiece& out_package_name, OutputStream* out,
OutputStream* out_r_txt) {
ClassDefinition r_class("R", ClassQualifier::kNone, true);
std::unique_ptr<MethodDefinition> rewrite_method;
std::unique_ptr<Printer> r_txt_printer;
if (out_r_txt != nullptr) {
r_txt_printer = util::make_unique<Printer>(out_r_txt);
}
// Generate an onResourcesLoaded() callback if requested.
if (options_.rewrite_callback_options) {
rewrite_method =
@@ -586,7 +600,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
rewrite_method.get(), out_r_txt)) {
rewrite_method.get(), r_txt_printer.get())) {
return false;
}
@@ -595,7 +609,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate);
if (priv_type) {
if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
rewrite_method.get(), out_r_txt)) {
rewrite_method.get(), r_txt_printer.get())) {
return false;
}
}
@@ -619,22 +633,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
}
AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder());
if (!ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out)) {
return false;
}
out->flush();
if (out_r_txt != nullptr) {
out_r_txt->flush();
if (!*out_r_txt) {
error_ = android::base::SystemErrorCodeToString(errno);
return false;
}
}
ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out);
return true;
}

View File

@@ -17,16 +17,16 @@
#ifndef AAPT_JAVA_CLASS_GENERATOR_H
#define AAPT_JAVA_CLASS_GENERATOR_H
#include <ostream>
#include <string>
#include "androidfw/StringPiece.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "androidfw/StringPiece.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
#include "text/Printer.h"
namespace aapt {
@@ -70,14 +70,14 @@ class JavaClassGenerator {
// All symbols technically belong to a single package, but linked libraries will
// have their names mangled, denoting that they came from a different package.
// We need to generate these symbols in a separate file. Returns true on success.
bool Generate(const android::StringPiece& package_name_to_generate, std::ostream* out,
std::ostream* out_r_txt = nullptr);
bool Generate(const android::StringPiece& package_name_to_generate, io::OutputStream* out,
io::OutputStream* out_r_txt = nullptr);
bool Generate(const android::StringPiece& package_name_to_generate,
const android::StringPiece& output_package_name, std::ostream* out,
std::ostream* out_r_txt = nullptr);
const android::StringPiece& output_package_name, io::OutputStream* out,
io::OutputStream* out_r_txt = nullptr);
const std::string& getError() const;
const std::string& GetError() const;
static std::string TransformToFieldName(const android::StringPiece& symbol);
@@ -94,13 +94,13 @@ class JavaClassGenerator {
bool ProcessType(const android::StringPiece& package_name_to_generate,
const ResourceTablePackage& package, const ResourceTableType& type,
ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def,
std::ostream* out_r_txt);
text::Printer* r_txt_printer);
// Writes a resource to the R.java file, optionally writing out a rewrite rule for its package
// ID if `out_rewrite_method` is not nullptr.
void ProcessResource(const ResourceNameRef& name, const ResourceId& id,
const ResourceEntry& entry, ClassDefinition* out_class_def,
MethodDefinition* out_rewrite_method, std::ostream* out_r_txt);
MethodDefinition* out_rewrite_method, text::Printer* r_txt_printer);
// Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for
// its package ID if `out_rewrite_method` is not nullptr.
@@ -109,7 +109,7 @@ class JavaClassGenerator {
const Styleable& styleable,
const android::StringPiece& package_name_to_generate,
ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
std::ostream* out_r_txt);
text::Printer* r_txt_printer);
IAaptContext* context_;
ResourceTable* table_;
@@ -117,7 +117,7 @@ class JavaClassGenerator {
std::string error_;
};
inline const std::string& JavaClassGenerator::getError() const {
inline const std::string& JavaClassGenerator::GetError() const {
return error_;
}

View File

@@ -16,12 +16,13 @@
#include "java/JavaClassGenerator.h"
#include <sstream>
#include <string>
#include "io/StringStream.h"
#include "test/Test.h"
#include "util/Util.h"
using ::aapt::io::StringOutputStream;
using ::android::StringPiece;
using ::testing::HasSubstr;
using ::testing::Lt;
@@ -45,7 +46,8 @@ TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
.Build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
std::string result;
StringOutputStream out(&result);
EXPECT_FALSE(generator.Generate("android", &out));
}
@@ -69,10 +71,10 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
.Build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
std::string output;
StringOutputStream out(&output);
EXPECT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, HasSubstr("public static final int hey_man=0x01020000;"));
EXPECT_THAT(output, HasSubstr("public static final int[] hey_dude={"));
@@ -93,10 +95,12 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
.SetNameManglerPolicy(NameManglerPolicy{"android"})
.Build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
std::string output = out.str();
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
out.Flush();
EXPECT_THAT(output, HasSubstr("package com.android.internal;"));
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
EXPECT_THAT(output, Not(HasSubstr("two")));
@@ -117,10 +121,12 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
.SetNameManglerPolicy(NameManglerPolicy{"android"})
.Build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
out.Flush();
EXPECT_THAT(output, HasSubstr("public static final class attr"));
EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private")));
}
@@ -147,9 +153,11 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
{
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
EXPECT_THAT(output, Not(HasSubstr("two")));
EXPECT_THAT(output, Not(HasSubstr("three")));
@@ -158,9 +166,11 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
{
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
EXPECT_THAT(output, Not(HasSubstr("three")));
@@ -169,9 +179,11 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
{
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;"));
@@ -235,10 +247,11 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
.Build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
std::string output;
StringOutputStream out(&output);
EXPECT_TRUE(generator.Generate("android", &out));
out.Flush();
std::string output = out.str();
EXPECT_THAT(output, HasSubstr("int foo_bar="));
EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar="));
}
@@ -258,9 +271,11 @@ TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
.SetNameManglerPolicy(NameManglerPolicy{"android"})
.Build();
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
const char* expected_text =
R"EOF(/**
@@ -298,9 +313,11 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent)
JavaClassGeneratorOptions options;
options.use_final = false;
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, HasSubstr("attr name android:one"));
EXPECT_THAT(output, HasSubstr("attr description"));
@@ -332,9 +349,11 @@ TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
JavaClassGeneratorOptions options;
JavaClassGenerator generator(context.get(), table.get(), {});
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
std::string::size_type actionbar_pos = output.find("int[] ActionBar");
ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
@@ -373,9 +392,11 @@ TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
JavaClassGeneratorOptions options;
options.use_final = false;
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, Not(HasSubstr("@attr name android:one")));
EXPECT_THAT(output, Not(HasSubstr("@attr description")));
@@ -409,10 +430,10 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary)
options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}};
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
std::string output;
StringOutputStream out(&output);
ASSERT_TRUE(generator.Generate("android", &out));
std::string output = out.str();
out.Flush();
EXPECT_THAT(output, HasSubstr("void onResourcesLoaded"));
EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded"));

View File

@@ -23,8 +23,7 @@
namespace aapt {
std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag,
xml::XmlResource* res);
std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
} // namespace aapt

View File

@@ -16,8 +16,10 @@
#include "java/ManifestClassGenerator.h"
#include "io/StringStream.h"
#include "test/Test.h"
using ::aapt::io::StringOutputStream;
using ::testing::HasSubstr;
using ::testing::Not;
@@ -144,12 +146,9 @@ static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xm
return ::testing::AssertionFailure() << "manifest_class == nullptr";
}
std::stringstream out;
if (!manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out)) {
return ::testing::AssertionFailure() << "failed to write java file";
}
*out_str = out.str();
StringOutputStream out(out_str);
manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out);
out.Flush();
return ::testing::AssertionSuccess();
}

View File

@@ -20,14 +20,18 @@
#include <string>
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
#include "JavaClassGenerator.h"
#include "ResourceUtils.h"
#include "ValueVisitor.h"
#include "androidfw/StringPiece.h"
#include "text/Printer.h"
#include "util/Util.h"
#include "xml/XmlDom.h"
using ::aapt::io::OutputStream;
using ::aapt::text::Printer;
namespace aapt {
namespace proguard {
@@ -326,12 +330,13 @@ bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set) {
return true;
}
bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) {
void WriteKeepSet(const KeepSet& keep_set, OutputStream* out) {
Printer printer(out);
for (const auto& entry : keep_set.manifest_class_set_) {
for (const UsageLocation& location : entry.second) {
*out << "# Referenced at " << location.source << "\n";
printer.Print("# Referenced at ").Println(location.source.to_string());
}
*out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
printer.Print("-keep class ").Print(entry.first).Println(" { <init>(...); }");
}
for (const auto& entry : keep_set.conditional_class_set_) {
@@ -342,26 +347,31 @@ bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) {
}
for (const UsageLocation& location : entry.second) {
*out << "# Referenced at " << location.source << "\n";
printer.Print("# Referenced at ").Println(location.source.to_string());
}
if (keep_set.conditional_keep_rules_ && can_be_conditional) {
*out << "-if class **.R$layout {\n";
printer.Println("-if class **.R$layout {");
printer.Indent();
for (const UsageLocation& location : locations) {
auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry);
*out << " int " << transformed_name << ";\n";
printer.Print("int ")
.Print(JavaClassGenerator::TransformToFieldName(location.name.entry))
.Println(";");
}
*out << "}\n";
printer.Undent();
printer.Println("}");
printer.Println();
}
*out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
printer.Print("-keep class ").Print(entry.first).Println(" { <init>(...); }");
printer.Println();
}
for (const auto& entry : keep_set.method_set_) {
for (const UsageLocation& location : entry.second) {
*out << "# Referenced at " << location.source << "\n";
printer.Print("# Referenced at ").Println(location.source.to_string());
}
*out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
printer.Print("-keepclassmembers class * { *** ").Print(entry.first).Println("(...); }");
printer.Println();
}
return true;
}
bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,

View File

@@ -22,11 +22,13 @@
#include <set>
#include <string>
#include "androidfw/StringPiece.h"
#include "Resource.h"
#include "ResourceTable.h"
#include "Source.h"
#include "ValueVisitor.h"
#include "androidfw/StringPiece.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
@@ -62,7 +64,7 @@ class KeepSet {
}
private:
friend bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set);
friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out);
friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
std::set<UsageLocation>* locations);
@@ -76,11 +78,12 @@ class KeepSet {
bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set,
bool main_dex_only = false);
bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table,
KeepSet* keep_set);
bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set);
bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);
void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out);
bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
std::set<UsageLocation>* locations);

View File

@@ -17,13 +17,23 @@
#include "java/ProguardRules.h"
#include "link/Linkers.h"
#include "io/StringStream.h"
#include "test/Test.h"
using ::aapt::io::StringOutputStream;
using ::testing::HasSubstr;
using ::testing::Not;
namespace aapt {
std::string GetKeepSetString(const proguard::KeepSet& set) {
std::string out;
StringOutputStream sout(&out);
proguard::WriteKeepSet(set, &sout);
sout.Flush();
return out;
}
TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
@@ -34,10 +44,8 @@ TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
proguard::KeepSet set;
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
}
@@ -50,10 +58,8 @@ TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
proguard::KeepSet set;
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
}
@@ -68,10 +74,8 @@ TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
proguard::KeepSet set;
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
}
@@ -87,10 +91,8 @@ TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
proguard::KeepSet set;
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
}
@@ -126,11 +128,10 @@ TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
ASSERT_TRUE(proguard::CollectProguardRules(bar_layout.get(), &set));
ASSERT_TRUE(proguard::CollectProguardRules(foo_layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
EXPECT_THAT(actual, HasSubstr("int foo"));
EXPECT_THAT(actual, HasSubstr("int bar"));
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
@@ -148,10 +149,9 @@ TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
EXPECT_THAT(actual, HasSubstr("int foo"));
EXPECT_THAT(actual, HasSubstr("int bar"));
@@ -170,11 +170,10 @@ TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, Not(HasSubstr("-if")));
EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
}
TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
@@ -187,10 +186,8 @@ TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
proguard::KeepSet set;
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("bar_method"));
}
@@ -208,10 +205,8 @@ TEST(ProguardRulesTest, MenuRulesAreEmitted) {
proguard::KeepSet set;
ASSERT_TRUE(proguard::CollectProguardRules(menu.get(), &set));
std::stringstream out;
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = GetKeepSetString(set);
std::string actual = out.str();
EXPECT_THAT(actual, HasSubstr("on_click"));
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));

View File

@@ -26,18 +26,18 @@ using ::android::StringPiece;
namespace aapt {
namespace text {
void Printer::Println(const StringPiece& str) {
Printer& Printer::Println(const StringPiece& str) {
Print(str);
Print("\n");
return Print("\n");
}
void Printer::Println() {
Print("\n");
Printer& Printer::Println() {
return Print("\n");
}
void Printer::Print(const StringPiece& str) {
Printer& Printer::Print(const StringPiece& str) {
if (error_) {
return;
return *this;
}
auto remaining_str_begin = str.begin();
@@ -53,7 +53,7 @@ void Printer::Print(const StringPiece& str) {
for (int i = 0; i < indent_level_; i++) {
if (!io::Copy(out_, " ")) {
error_ = true;
return;
return *this;
}
}
needs_indent_ = false;
@@ -61,7 +61,7 @@ void Printer::Print(const StringPiece& str) {
if (!io::Copy(out_, str_to_copy)) {
error_ = true;
return;
return *this;
}
}
@@ -69,7 +69,7 @@ void Printer::Print(const StringPiece& str) {
if (new_line_iter != remaining_str_end) {
if (!io::Copy(out_, "\n")) {
error_ = true;
return;
return *this;
}
needs_indent_ = true;
// Ok to increment iterator here because we know that the '\n' character is one byte.
@@ -78,6 +78,7 @@ void Printer::Print(const StringPiece& str) {
remaining_str_begin = new_line_iter;
}
}
return *this;
}
void Printer::Indent() {

View File

@@ -31,9 +31,9 @@ class Printer {
explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
}
void Print(const ::android::StringPiece& str);
void Println(const ::android::StringPiece& str);
void Println();
Printer& Print(const ::android::StringPiece& str);
Printer& Println(const ::android::StringPiece& str);
Printer& Println();
void Indent();
void Undent();