#define AAPT_JAVA_CLASSDEFINITION_H
#include <ostream>
+#include <set>
#include <string>
#include "android-base/macros.h"
public:
virtual ~ClassMember() = default;
- AnnotationProcessor* GetCommentBuilder() { return &processor_; }
+ AnnotationProcessor* GetCommentBuilder() {
+ return &processor_;
+ }
virtual bool empty() const = 0;
+ virtual const std::string& GetName() const = 0;
+
// Writes the class member to the out stream. 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.
PrimitiveMember(const android::StringPiece& name, const T& val)
: name_(name.to_string()), val_(val) {}
- bool empty() const override { return false; }
+ bool empty() const override {
+ return false;
+ }
+
+ const std::string& GetName() const override {
+ return name_;
+ }
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
PrimitiveMember(const android::StringPiece& name, const std::string& val)
: name_(name.to_string()), val_(val) {}
- bool empty() const override { return false; }
+ bool empty() const override {
+ return false;
+ }
+
+ const std::string& GetName() const override {
+ return name_;
+ }
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
public:
explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
- void AddElement(const T& val) { elements_.push_back(val); }
+ void AddElement(const T& val) {
+ elements_.push_back(val);
+ }
- bool empty() const override { return false; }
+ bool empty() const override {
+ return false;
+ }
+
+ const std::string& GetName() const override {
+ return name_;
+ }
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
// formatting may be broken.
void AppendStatement(const android::StringPiece& statement);
+ // Not quite the same as a name, but good enough.
+ const std::string& GetName() const override {
+ return signature_;
+ }
+
// Even if the method is empty, we always want to write the method signature.
bool empty() const override { return false; }
ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
: name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
- void AddMember(std::unique_ptr<ClassMember> member) {
- members_.push_back(std::move(member));
- }
+ enum class Result {
+ kAdded,
+ kOverridden,
+ };
+
+ Result AddMember(std::unique_ptr<ClassMember> member);
bool empty() const override;
+
+ const std::string& GetName() const override {
+ return name_;
+ }
+
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override;
private:
+ struct ClassMemberCompare {
+ using T = std::unique_ptr<ClassMember>;
+ bool operator()(const T& a, const T& b) const {
+ return a->GetName() < b->GetName();
+ }
+ };
+
std::string name_;
ClassQualifier qualifier_;
bool create_if_empty_;
- std::vector<std::unique_ptr<ClassMember>> members_;
+ std::set<std::unique_ptr<ClassMember>, ClassMemberCompare> members_;
DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
};
EXPECT_THAT(actual, HasSubstr(expected_secret));
}
+// This is bad but part of public API behaviour so we need to preserve it.
+TEST(ManifestClassGeneratorTest, LastSeenPermissionWithSameLeafNameTakesPrecedence) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+ <permission android:name="android.permission.ACCESS_INTERNET" />
+ <permission android:name="com.android.aapt.test.ACCESS_INTERNET" />
+ </manifest>)");
+
+ std::string actual;
+ ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), &actual));
+ EXPECT_THAT(actual, HasSubstr("ACCESS_INTERNET=\"com.android.aapt.test.ACCESS_INTERNET\";"));
+ EXPECT_THAT(actual, Not(HasSubstr("ACCESS_INTERNET=\"android.permission.ACCESS_INTERNET\";")));
+}
+
static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xml::XmlResource* res,
std::string* out_str) {
std::unique_ptr<ClassDefinition> manifest_class =