libredex/Resolver.cpp (155 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Resolver.h"
#include "DexUtil.h"
namespace {
inline bool match(const DexString* name,
const DexProto* proto,
const DexMethod* cls_meth) {
return name == cls_meth->get_name() && proto == cls_meth->get_proto();
}
DexMethod* resolve_intf_method_ref(const DexClass* cls,
const DexString* name,
const DexProto* proto) {
auto find_method = [&](const DexClass* cls) -> DexMethod* {
const auto& vmethods = cls->get_vmethods();
for (const auto vmethod : vmethods) {
if (vmethod->get_name() == name && vmethod->get_proto() == proto) {
return vmethod;
}
}
return nullptr;
};
auto method = find_method(cls);
if (method) return method;
for (const auto& super_intf : *cls->get_interfaces()) {
const auto& super_intf_cls = type_class(super_intf);
if (super_intf_cls == nullptr) continue;
method = resolve_intf_method_ref(super_intf_cls, name, proto);
if (method) return method;
}
return nullptr;
}
} // namespace
DexMethod* resolve_method(const DexClass* cls,
const DexString* name,
const DexProto* proto,
MethodSearch search,
const DexMethod* caller) {
if (search == MethodSearch::Interface) {
return resolve_intf_method_ref(cls, name, proto);
}
if (search == MethodSearch::Super) {
if (caller) {
// caller must be provided. This condition is here to be compatible with
// old behavior.
DexType* containing_type = caller->get_class();
DexClass* containing_class = type_class(containing_type);
if (containing_class == nullptr) return nullptr;
DexType* super_class = containing_class->get_super_class();
if (!super_class) return nullptr;
cls = type_class(super_class);
}
// The rest is the same as virtual.
search = MethodSearch::Virtual;
}
while (cls) {
if (search == MethodSearch::InterfaceVirtual) {
auto try_intf = resolve_intf_method_ref(cls, name, proto);
if (try_intf) {
return try_intf;
}
}
if (search == MethodSearch::Virtual || search == MethodSearch::Any) {
for (auto& vmeth : cls->get_vmethods()) {
if (match(name, proto, vmeth)) {
return vmeth;
}
}
}
if (search == MethodSearch::Direct || search == MethodSearch::Static ||
search == MethodSearch::Any) {
for (auto& dmeth : cls->get_dmethods()) {
if (match(name, proto, dmeth)) {
return dmeth;
}
}
}
// direct methods only look up the given class
cls = search != MethodSearch::Direct ? type_class(cls->get_super_class())
: nullptr;
}
return nullptr;
}
DexMethod* resolve_method_ref(const DexClass* cls,
const DexString* name,
const DexProto* proto,
MethodSearch search) {
always_assert(search != MethodSearch::Super);
if (search != MethodSearch::Interface) {
const auto& super = cls->get_super_class();
if (super == nullptr) return nullptr;
const auto& super_cls = type_class(super);
auto resolved = resolve_method(super_cls, name, proto, search);
if (resolved || search != MethodSearch::InterfaceVirtual) {
return resolved;
}
}
for (const auto& super_intf : *cls->get_interfaces()) {
const auto& super_intf_cls = type_class(super_intf);
if (super_intf_cls == nullptr) continue;
auto method = resolve_intf_method_ref(super_intf_cls, name, proto);
if (method) return method;
}
return nullptr;
}
DexField* resolve_field(const DexType* owner,
const DexString* name,
const DexType* type,
FieldSearch fs) {
auto field_eq = [&](const DexField* a) {
return a->get_name() == name && a->get_type() == type;
};
const DexClass* cls = type_class(owner);
while (cls) {
if (fs == FieldSearch::Instance || fs == FieldSearch::Any) {
for (auto ifield : cls->get_ifields()) {
if (field_eq(ifield)) {
return ifield;
}
}
}
if (fs == FieldSearch::Static || fs == FieldSearch::Any) {
for (auto sfield : cls->get_sfields()) {
if (field_eq(sfield)) {
return sfield;
}
}
// static final fields may be coming from interfaces so we
// have to walk up the interface hierarchy too
for (const auto& intf : *cls->get_interfaces()) {
auto field = resolve_field(intf, name, type, fs);
if (field != nullptr) return field;
}
}
cls = type_class(cls->get_super_class());
}
return nullptr;
}
DexMethod* find_top_impl(const DexClass* cls,
const DexString* name,
const DexProto* proto) {
DexMethod* top_impl = nullptr;
while (cls) {
for (const auto& vmeth : cls->get_vmethods()) {
if (match(name, proto, vmeth)) {
top_impl = vmeth;
}
}
cls = type_class(cls->get_super_class());
}
return top_impl;
}
DexMethod* find_top_intf_impl(const DexClass* cls,
const DexString* name,
const DexProto* proto) {
DexMethod* top_impl = nullptr;
while (cls) {
DexMethod* top_mir_impl = resolve_intf_method_ref(cls, name, proto);
if (top_mir_impl != nullptr) top_impl = top_mir_impl;
cls = type_class(cls->get_super_class());
}
return top_impl;
}