Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 466df70c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Fix R.java styleable + indices ordering"

parents 4ba2c3b7 761d4341
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -41,18 +41,21 @@ void MethodDefinition::WriteToStream(const StringPiece& prefix, bool final,

ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
  Result result = Result::kAdded;
  auto iter = members_.find(member);
  if (iter != members_.end()) {
    members_.erase(iter);
  auto iter = indexed_members_.find(member->GetName());
  if (iter != indexed_members_.end()) {
    // Overwrite the entry.
    ordered_members_[iter->second].reset();
    result = Result::kOverridden;
  }
  members_.insert(std::move(member));

  indexed_members_[member->GetName()] = ordered_members_.size();
  ordered_members_.push_back(std::move(member));
  return result;
}

bool ClassDefinition::empty() const {
  for (const std::unique_ptr<ClassMember>& member : members_) {
    if (!member->empty()) {
  for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
    if (member != nullptr && !member->empty()) {
      return false;
    }
  }
@@ -61,7 +64,7 @@ bool ClassDefinition::empty() const {

void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
                                    std::ostream* out) const {
  if (members_.empty() && !create_if_empty_) {
  if (empty() && !create_if_empty_) {
    return;
  }

@@ -76,10 +79,15 @@ void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
  std::string new_prefix = prefix.to_string();
  new_prefix.append(kIndent);

  for (const std::unique_ptr<ClassMember>& member : members_) {
  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";
    }
  }

  *out << prefix << "}";
}
+19 −23
Original line number Diff line number Diff line
@@ -18,8 +18,9 @@
#define AAPT_JAVA_CLASSDEFINITION_H

#include <ostream>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>

#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
@@ -73,21 +74,18 @@ class PrimitiveMember : public ClassMember {
  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_ << ";";
    *out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
         << ";";
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);

  std::string name_;
  T val_;

  DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};

/**
 * Specialization for strings so they get the right type and are quoted with "".
 */
// Specialization for strings so they get the right type and are quoted with "".
template <>
class PrimitiveMember<std::string> : public ClassMember {
 public:
@@ -111,10 +109,10 @@ class PrimitiveMember<std::string> : public ClassMember {
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);

  std::string name_;
  std::string val_;

  DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};

using IntMember = PrimitiveMember<uint32_t>;
@@ -160,10 +158,10 @@ class PrimitiveArrayMember : public ClassMember {
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);

  std::string name_;
  std::vector<T> elements_;

  DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
};

using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
@@ -185,12 +183,16 @@ class MethodDefinition : public ClassMember {
  }

  // Even if the method is empty, we always want to write the method signature.
  bool empty() const override { return false; }
  bool empty() const override {
    return false;
  }

  void WriteToStream(const android::StringPiece& prefix, bool final,
                     std::ostream* out) const override;

 private:
  DISALLOW_COPY_AND_ASSIGN(MethodDefinition);

  std::string signature_;
  std::vector<std::string> statements_;
};
@@ -222,19 +224,13 @@ class ClassDefinition : public ClassMember {
                     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();
    }
  };
  DISALLOW_COPY_AND_ASSIGN(ClassDefinition);

  std::string name_;
  ClassQualifier qualifier_;
  bool create_if_empty_;
  std::set<std::unique_ptr<ClassMember>, ClassMemberCompare> members_;

  DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
  std::vector<std::unique_ptr<ClassMember>> ordered_members_;
  std::unordered_map<android::StringPiece, size_t> indexed_members_;
};

}  // namespace aapt
+49 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@

using ::android::StringPiece;
using ::testing::HasSubstr;
using ::testing::Lt;
using ::testing::Ne;
using ::testing::Not;

namespace aapt {
@@ -306,6 +308,53 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent)
  EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
}

TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
  std::unique_ptr<ResourceTable> table =
      test::ResourceTableBuilder()
          .SetPackageId("android", 0x01)
          .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
          .AddValue("android:attr/background", util::make_unique<Attribute>())
          .AddValue("android:styleable/ActionBar",
                    test::StyleableBuilder()
                        .AddItem("android:attr/background", ResourceId(0x01010000))
                        .Build())
          .AddValue("android:styleable/ActionBar.LayoutParams",
                    test::StyleableBuilder()
                        .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
                        .Build())
          .Build();

  std::unique_ptr<IAaptContext> context =
      test::ContextBuilder()
          .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
          .SetNameManglerPolicy(NameManglerPolicy{"android"})
          .Build();

  JavaClassGeneratorOptions options;
  JavaClassGenerator generator(context.get(), table.get(), {});
  std::stringstream out;
  ASSERT_TRUE(generator.Generate("android", &out));
  std::string output = out.str();

  std::string::size_type actionbar_pos = output.find("int[] ActionBar");
  ASSERT_THAT(actionbar_pos, Ne(std::string::npos));

  std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
  ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));

  std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
  ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));

  std::string::size_type actionbar_layout_params_layout_gravity_pos =
      output.find("int ActionBar_LayoutParams_layout_gravity");
  ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));

  EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
  EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
  EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
  EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
}

TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
  Attribute attr(false);
  attr.SetComment(StringPiece("removed"));