InstructionCallGraphInformation process_instruction()

in source/CallGraph.cpp [254:359]


InstructionCallGraphInformation process_instruction(
    const Method* caller,
    const IRInstruction* instruction,
    ConcurrentSet<const Method*>& worklist,
    ConcurrentSet<const Method*>& processed,
    const Options& options,
    Methods& method_factory,
    Fields& field_factory,
    const Types& types,
    Overrides& override_factory,
    const Features& features) {
  InstructionCallGraphInformation instruction_information;

  if (opcode::is_an_iput(instruction->opcode())) {
    // Add artificial calls to all methods in an anonymous class.
    const auto* iput_type =
        types.source_type(caller, instruction, /* source_position */ 0);
    if (iput_type && is_anonymous_class(iput_type)) {
      auto artificial_callees_for_instruction =
          anonymous_class_artificial_callees(
              method_factory,
              instruction,
              iput_type,
              /* register */ instruction->src(0),
              /* features */
              FeatureSet{features.get("via-anonymous-class-to-field")});

      if (!artificial_callees_for_instruction.empty()) {
        instruction_information.artificial_callees =
            std::move(artificial_callees_for_instruction);
      }
    }

    const auto* field = resolve_field_access(caller, instruction);
    if (field != nullptr) {
      instruction_information.field_access = field_factory.get(field);
    }
    return instruction_information;
  }

  if (opcode::is_an_iget(instruction->opcode()) ||
      opcode::is_an_sget(instruction->opcode()) ||
      opcode::is_an_sput(instruction->opcode())) {
    const auto* field = resolve_field_access(caller, instruction);
    if (field != nullptr) {
      instruction_information.field_access = field_factory.get(field);
    }
    return instruction_information;
  }

  if (!opcode::is_an_invoke(instruction->opcode())) {
    return instruction_information;
  }

  const DexMethod* dex_callee = resolve_call(types, caller, instruction);
  if (!dex_callee) {
    return instruction_information;
  }

  ParameterTypeOverrides parameter_type_overrides =
      anonymous_class_arguments(types, caller, instruction, dex_callee);

  const auto* callee = get_callee_from_resolved_call(
      dex_callee,
      instruction,
      parameter_type_overrides,
      options,
      method_factory,
      features,
      instruction_information.artificial_callees);

  instruction_information.callee = callee;

  if (callee->parameter_type_overrides().empty() ||
      processed.count(callee) != 0) {
    return instruction_information;
  }
  // This is a newly introduced method with parameter type
  // overrides. We need to generate it's method overrides,
  // and compute callees for them.
  const Method* original_callee = method_factory.get(callee->dex_method());
  std::unordered_set<const Method*> original_methods =
      override_factory.get(original_callee);
  original_methods.insert(original_callee);

  for (const Method* original_method : original_methods) {
    const Method* method = method_factory.create(
        original_method->dex_method(), callee->parameter_type_overrides());

    std::unordered_set<const Method*> overrides;
    for (const Method* original_override :
         override_factory.get(original_method)) {
      overrides.insert(method_factory.create(
          original_override->dex_method(), callee->parameter_type_overrides()));
    }

    if (!overrides.empty()) {
      override_factory.set(method, std::move(overrides));
    }

    if (processed.count(method) == 0) {
      worklist.insert(method);
    }
  }
  return instruction_information;
}