Add ClassIterator

Add a way to iterate over all of the classes in a Dex file. The
iterator returns a ClassAccessor for each class.

Added DexFile::GetClasses to return an iteration range for this new
iterator type.

Sample usage:
for (ClassAccessor accessor : dex_file.GetClasses()) {

Bug: 79758018
Bug: 77709234
Test: test-art-host
Change-Id: I66e000aa11f433e72f6857496f4e89a0b811f5a2
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index bcd0a7b..5cfbcaa 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -20,19 +20,22 @@
 #include "class_accessor.h"
 
 #include "base/leb128.h"
+#include "class_iterator.h"
+#include "code_item_accessors-inl.h"
 
 namespace art {
 
-inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def)
-    : ClassAccessor(dex_file, dex_file.GetClassData(class_def)) {}
+inline ClassAccessor::ClassAccessor(const ClassIteratorData& data)
+    : ClassAccessor(data.dex_file_, data.dex_file_.GetClassDef(data.class_def_idx_)) {}
 
-inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const uint8_t* class_data)
+inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def)
     : dex_file_(dex_file),
-      ptr_pos_(class_data),
-      num_static_fields_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
-      num_instance_fields_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
-      num_direct_methods_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
-      num_virtual_methods_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
+      descriptor_index_(class_def.class_idx_),
+      ptr_pos_(dex_file.GetClassData(class_def)),
+      num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
+      num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
+      num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
+      num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
 
 inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) {
   method_idx_ += DecodeUnsignedLeb128(&ptr);
@@ -57,25 +60,33 @@
     const DirectMethodVisitor& direct_method_visitor,
     const VirtualMethodVisitor& virtual_method_visitor) const {
   const uint8_t* ptr = ptr_pos_;
-  for (size_t i = 0; i < num_static_fields_; ++i) {
+  {
     Field data;
-    ptr = data.Read(ptr);
-    static_field_visitor(data);
+    for (size_t i = 0; i < num_static_fields_; ++i) {
+      ptr = data.Read(ptr);
+      static_field_visitor(data);
+    }
   }
-  for (size_t i = 0; i < num_instance_fields_; ++i) {
+  {
     Field data;
-    ptr = data.Read(ptr);
-    instance_field_visitor(data);
+    for (size_t i = 0; i < num_instance_fields_; ++i) {
+      ptr = data.Read(ptr);
+      instance_field_visitor(data);
+    }
   }
-  for (size_t i = 0; i < num_direct_methods_; ++i) {
-    Method data;
-    ptr = data.Read(ptr);
-    direct_method_visitor(data);
+  {
+    Method data(dex_file_);
+    for (size_t i = 0; i < num_direct_methods_; ++i) {
+      ptr = data.Read(ptr);
+      direct_method_visitor(data);
+    }
   }
-  for (size_t i = 0; i < num_virtual_methods_; ++i) {
-    Method data;
-    ptr = data.Read(ptr);
-    virtual_method_visitor(data);
+  {
+    Method data(dex_file_);
+    for (size_t i = 0; i < num_virtual_methods_; ++i) {
+      ptr = data.Read(ptr);
+      virtual_method_visitor(data);
+    }
   }
 }
 
@@ -99,6 +110,10 @@
   return dex_file_.GetCodeItem(method.GetCodeItemOffset());
 }
 
+inline CodeItemInstructionAccessor ClassAccessor::Method::GetInstructions() const {
+  return CodeItemInstructionAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset()));
+}
+
 }  // namespace art
 
 #endif  // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index 59a6b5d..835c4e2 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -18,10 +18,13 @@
 #define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_
 
 #include "base/utils.h"
+#include "code_item_accessors.h"
 #include "dex_file.h"
 
 namespace art {
 
+class ClassIteratorData;
+
 // Classes to access Dex data.
 class ClassAccessor {
  public:
@@ -40,10 +43,15 @@
       return code_off_;
     }
 
+    CodeItemInstructionAccessor GetInstructions() const;
+
    private:
+    explicit Method(const DexFile& dex_file) : dex_file_(dex_file) {}
+
     const uint8_t* Read(const uint8_t* ptr);
 
     // A decoded version of the method of a class_data_item.
+    const DexFile& dex_file_;
     uint32_t method_idx_ = 0u;
     uint32_t access_flags_ = 0u;
     uint32_t code_off_ = 0u;
@@ -72,7 +80,10 @@
     friend class ClassAccessor;
   };
 
-  ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def);
+  // Not explicit specifically for range-based loops.
+  ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data);
+
+  ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def);
 
   // Return the code item for a method.
   const DexFile::CodeItem* GetCodeItem(const Method& method) const;
@@ -112,18 +123,19 @@
     return num_virtual_methods_;
   }
 
- protected:
-  ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const uint8_t* class_data);
+  // TODO: Deprecate
+  dex::TypeIndex GetDescriptorIndex() const {
+    return descriptor_index_;
+  }
 
+ protected:
   const DexFile& dex_file_;
+  const dex::TypeIndex descriptor_index_ = {};
   const uint8_t* ptr_pos_ = nullptr;  // Pointer into stream of class_data_item.
   const uint32_t num_static_fields_ = 0u;
   const uint32_t num_instance_fields_ = 0u;
   const uint32_t num_direct_methods_ = 0u;
   const uint32_t num_virtual_methods_ = 0u;
-  // Only cache descriptor.
-  const void* class_def_ = nullptr;
-  const void* class_data_ = nullptr;
 };
 
 }  // namespace art
diff --git a/libdexfile/dex/class_iterator.h b/libdexfile/dex/class_iterator.h
new file mode 100644
index 0000000..477c93b
--- /dev/null
+++ b/libdexfile/dex/class_iterator.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_
+#define ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_
+
+#include "base/logging.h"
+
+namespace art {
+
+class ClassAccessor;
+class ClassIterator;
+class DexFile;
+
+// Holder class, used to construct ClassAccessors.
+class ClassIteratorData {
+ public:
+  ClassIteratorData(const DexFile& dex_file, uint32_t class_def_idx)
+      : dex_file_(dex_file),
+        class_def_idx_(class_def_idx) {}
+
+ private:
+  const DexFile& dex_file_;
+  uint32_t class_def_idx_ = 0u;
+
+  friend class ClassAccessor;
+  friend class ClassIterator;
+};
+
+// Iterator for visiting classes in a Dex file.
+class ClassIterator : public std::iterator<std::forward_iterator_tag, ClassIteratorData> {
+ public:
+  using value_type = std::iterator<std::forward_iterator_tag, ClassIteratorData>::value_type;
+  using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type;
+
+  ClassIterator(const DexFile& dex_file, uint32_t class_def_idx)
+      : data_(dex_file, class_def_idx) {}
+
+  // Value after modification.
+  ClassIterator& operator++() {
+    ++data_.class_def_idx_;
+    return *this;
+  }
+
+  // Value before modification.
+  ClassIterator operator++(int) {
+    ClassIterator temp = *this;
+    ++*this;
+    return temp;
+  }
+
+  const value_type& operator*() const {
+    return data_;
+  }
+
+  bool operator==(const ClassIterator& rhs) const {
+    DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files.";
+    return data_.class_def_idx_ == rhs.data_.class_def_idx_;
+  }
+
+  bool operator!=(const ClassIterator& rhs) const {
+    return !(*this == rhs);
+  }
+
+  bool operator<(const ClassIterator& rhs) const {
+    DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files.";
+    return data_.class_def_idx_ < rhs.data_.class_def_idx_;
+  }
+
+  bool operator>(const ClassIterator& rhs) const {
+    return rhs < *this;
+  }
+
+  bool operator<=(const ClassIterator& rhs) const {
+    return !(rhs < *this);
+  }
+
+  bool operator>=(const ClassIterator& rhs) const {
+    return !(*this < rhs);
+  }
+
+ protected:
+  ClassIteratorData data_;
+};
+
+}  // namespace art
+
+#endif  // ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_
diff --git a/libdexfile/dex/code_item_accessors.h b/libdexfile/dex/code_item_accessors.h
index ba7c126..5786d3f 100644
--- a/libdexfile/dex/code_item_accessors.h
+++ b/libdexfile/dex/code_item_accessors.h
@@ -47,6 +47,11 @@
     return insns_size_in_code_units_;
   }
 
+  uint32_t InsnsSizeInBytes() const {
+    static constexpr uint32_t kCodeUnitSizeInBytes = 2u;
+    return insns_size_in_code_units_ * kCodeUnitSizeInBytes;
+  }
+
   const uint16_t* Insns() const {
     return insns_;
   }
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index e78e8d7..f5dd374 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -20,6 +20,7 @@
 #include "base/casts.h"
 #include "base/leb128.h"
 #include "base/stringpiece.h"
+#include "class_iterator.h"
 #include "compact_dex_file.h"
 #include "dex_file.h"
 #include "invoke_type.h"
@@ -527,6 +528,10 @@
   }
 }
 
+inline IterationRange<ClassIterator> DexFile::GetClasses() const {
+  return { ClassIterator(*this, 0u), ClassIterator(*this, NumClassDefs()) };
+}
+
 }  // namespace art
 
 #endif  // ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 87d2c48..f1f8b50 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -27,6 +27,7 @@
 #include "base/iteration_range.h"
 #include "base/macros.h"
 #include "base/value_object.h"
+#include "class_iterator.h"
 #include "dex_file_types.h"
 #include "dex_instruction_iterator.h"
 #include "hidden_api_access_flags.h"
@@ -1012,6 +1013,8 @@
   // Changes the dex file pointed to by class_it to not have any hiddenapi flags.
   static void UnHideAccessFlags(ClassDataItemIterator& class_it);
 
+  inline IterationRange<ClassIterator> GetClasses() const;
+
  protected:
   // First Dex format version supporting default methods.
   static const uint32_t kDefaultMethodsVersion = 37;