source/MethodContext.cpp (103 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 <mariana-trench/MethodContext.h>
#include <Show.h>
#include <mariana-trench/Log.h>
#include <mariana-trench/Overrides.h>
namespace marianatrench {
MethodContext::MethodContext(
Context& context,
const Registry& registry,
Model& model)
: options(*context.options),
artificial_methods(*context.artificial_methods),
methods(*context.methods),
fields(*context.fields),
positions(*context.positions),
types(*context.types),
class_properties(*context.class_properties),
overrides(*context.overrides),
call_graph(*context.call_graph),
rules(*context.rules),
dependencies(*context.dependencies),
scheduler(*context.scheduler),
kinds(*context.kinds),
features(*context.features),
registry(registry),
memory_factory(model.method()),
model(model),
context_(context) {
std::string method_name = show(model.method());
const auto& log_methods = options.log_methods();
dump_ = std::any_of(
log_methods.begin(), log_methods.end(), [&](const auto& pattern) {
return method_name.find(pattern) != std::string::npos;
});
}
Model MethodContext::model_at_callsite(
const CallTarget& call_target,
const Position* position,
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
const std::vector<std::optional<std::string>>& source_constant_arguments)
const {
auto* caller = method();
LOG_OR_DUMP(
this,
5,
"Getting model for {} call `{}`",
(call_target.is_virtual() ? "virtual" : "static"),
show(call_target.resolved_base_callee()));
if (!call_target.resolved()) {
return Model(
/* method */ nullptr,
context_,
Model::Mode::SkipAnalysis | Model::Mode::AddViaObscureFeature |
Model::Mode::TaintInTaintOut);
}
if (call_target.is_virtual()) {
auto cached = callsite_model_cache_.find(CacheKey{call_target, position});
if (cached != callsite_model_cache_.end()) {
return cached->second;
}
}
auto model = registry.get(call_target.resolved_base_callee())
.at_callsite(
caller,
position,
context_,
source_register_types,
source_constant_arguments);
if (!call_target.is_virtual()) {
return model;
}
if (model.no_join_virtual_overrides()) {
LOG_OR_DUMP(
this,
5,
"Not joining at call-site for method `{}`",
show(call_target.resolved_base_callee()));
return model;
}
LOG_OR_DUMP(
this,
5,
"Initial model for `{}`: {}",
show(call_target.resolved_base_callee()),
model);
for (const auto* override : call_target.overrides()) {
auto override_model = registry.get(override).at_callsite(
caller,
position,
context_,
source_register_types,
source_constant_arguments);
LOG_OR_DUMP(
this,
5,
"Joining with model for `{}`: {}",
show(override),
override_model);
model.join_with(override_model);
}
callsite_model_cache_.emplace(CacheKey{call_target, position}, model);
return model;
}
} // namespace marianatrench