source/Method.cpp (151 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 <DexAccess.h> #include <DexUtil.h> #include <Show.h> #include <mariana-trench/Assert.h> #include <mariana-trench/JsonValidation.h> #include <mariana-trench/Method.h> #include <mariana-trench/Methods.h> #include <mariana-trench/Redex.h> namespace marianatrench { Method::Method( const DexMethod* method, ParameterTypeOverrides parameter_type_overrides) : method_(method), parameter_type_overrides_(std::move(parameter_type_overrides)), signature_(::show(method)), show_cached_(::show(this)) { mt_assert(method != nullptr); } bool Method::operator==(const Method& other) const { return method_ == other.method_ && parameter_type_overrides_ == other.parameter_type_overrides_; } const IRCode* Method::get_code() const { return method_->get_code(); } DexType* Method::get_class() const { return method_->get_class(); } DexProto* Method::get_proto() const { return method_->get_proto(); } const std::string& Method::get_name() const { return method_->get_name()->str(); } DexAccessFlags Method::get_access() const { return method_->get_access(); } bool Method::is_public() const { return ::is_public(method_); } bool Method::is_static() const { return ::is_static(method_); } bool Method::is_native() const { return ::is_native(method_); } bool Method::is_interface() const { return ::is_interface(method_); } bool Method::is_constructor() const { return method::is_init(method_); } bool Method::returns_void() const { return method_->get_proto()->get_rtype() == type::_void(); } const std::string& Method::signature() const { return signature_; } const std::string& Method::show() const { return show_cached_; } ParameterPosition Method::number_of_parameters() const { return static_cast<ParameterPosition>( method_->get_proto()->get_args()->size()) + first_parameter_index(); } DexType* MT_NULLABLE Method::parameter_type(ParameterPosition argument) const { const auto* dex_arguments = method_->get_proto()->get_args(); // We treat "this/self" for instance methods as argument 0 // This must be consistent with Method::number_of_parameters if (!is_static()) { if (argument == 0u) { return method_->get_class(); } else { argument--; } } static_assert(std::is_unsigned_v<ParameterPosition>); return (argument < dex_arguments->size()) ? dex_arguments->at(argument) : nullptr; } DexType* Method::return_type() const { return method_->get_proto()->get_rtype(); } ParameterPosition Method::first_parameter_index() const { return is_static() ? 0u : 1u; } const Method* Method::from_json(const Json::Value& value, Context& context) { if (value.isString()) { // Simpler form, less verbose. auto* dex_method = redex::get_method(value.asString()); if (!dex_method) { throw JsonValidationError( value, /* field */ std::nullopt, /* expected */ "existing method name"); } return context.methods->create(dex_method); } if (!value.isObject()) { throw JsonValidationError( value, /* field */ std::nullopt, /* expected */ "object or string"); } auto method_name = JsonValidation::string(value, "name"); auto* dex_method = redex::get_method(method_name); if (!dex_method) { throw JsonValidationError( value, /* field */ "name", /* expected */ "existing method name"); } ParameterTypeOverrides parameter_type_overrides; for (auto parameter_type_override : JsonValidation::null_or_array(value, "parameter_type_overrides")) { auto parameter = JsonValidation::integer(parameter_type_override, "parameter"); auto* type = JsonValidation::dex_type(parameter_type_override, "type"); parameter_type_overrides.emplace(parameter, type); } return context.methods->create(dex_method, parameter_type_overrides); } Json::Value Method::to_json() const { if (parameter_type_overrides_.empty()) { // Use a simpler form to be less verbose. return Json::Value(signature_); } auto value = Json::Value(Json::objectValue); value["name"] = Json::Value(signature_); auto parameter_type_overrides = Json::Value(Json::arrayValue); for (auto [parameter, type] : parameter_type_overrides_) { auto parameter_type_override = Json::Value(Json::objectValue); parameter_type_override["parameter"] = Json::Value(static_cast<int>(parameter)); parameter_type_override["type"] = Json::Value(::show(type)); parameter_type_overrides.append(parameter_type_override); } value["parameter_type_overrides"] = parameter_type_overrides; return value; } std::ostream& operator<<(std::ostream& out, const Method& method) { out << method.signature_; if (!method.parameter_type_overrides_.empty()) { out << "["; for (auto iterator = method.parameter_type_overrides_.begin(), end = method.parameter_type_overrides_.end(); iterator != end;) { out << iterator->first << ": " << show(iterator->second); ++iterator; if (iterator != end) { out << ","; } } out << "]"; } return out; } } // namespace marianatrench