Model MethodContext::model_at_callsite()

in source/MethodContext.cpp [47:123]


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;
}