<commit_before>(*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

open! IStd
module F = Format

(** Translate declarations **)

module L = Logging

module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFrontend = struct
  (** Translates the method/function's body into nodes of the cfg. *)
  let add_method ?(is_destructor_wrapper = false) trans_unit_ctx tenv cfg class_decl_opt procname
      body ms has_return_param outer_context_opt extra_instrs =
    L.(debug Capture Verbose)
      "@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Procname.pp procname ;
    incr CFrontend_config.procedures_attempted ;
    let recover () =
      incr CFrontend_config.procedures_failed ;
      Procname.Hash.remove cfg procname ;
      let method_kind = ms.CMethodSignature.method_kind in
      CMethod_trans.create_external_procdesc trans_unit_ctx cfg procname method_kind None
    in
    let pp_context fmt () =
      F.fprintf fmt "Aborting translation of method '%a' in file '%a'" Procname.pp procname
        SourceFile.pp trans_unit_ctx.CFrontend_config.source_file
    in
    let f () =
      match Procname.Hash.find_opt cfg procname with
      | Some procdesc when Procdesc.is_defined procdesc && not (BiabductionModels.mem procname) ->
          L.(debug Capture Verbose)
            "@\n@\n>>---------- Start translating body of function: '%s' ---------<<@\n@."
            (Procname.to_string procname) ;
          let vars_to_destroy = CScope.Variables.compute_vars_to_destroy_map body in
          let context =
            CContext.create_context trans_unit_ctx tenv cfg procdesc class_decl_opt has_return_param
              outer_context_opt vars_to_destroy
          in
          let start_node = Procdesc.get_start_node procdesc in
          let exit_node = Procdesc.get_exit_node procdesc in
          let meth_body_nodes =
            T.instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper
          in
          Procdesc.node_set_succs procdesc start_node ~normal:meth_body_nodes ~exn:[]
      | _ ->
          ()
    in
    CFrontend_errors.protect ~f ~recover ~pp_context


  let function_decl trans_unit_ctx tenv cfg func_decl block_data_opt =
    try
      let captured_vars, outer_context_opt =
        match block_data_opt with
        | Some {CModule_type.captured_vars; context= outer_context} ->
            (captured_vars, Some outer_context)
        | None ->
            ([], None)
      in
      let passed_as_noescape_block_to, procname, block_return_type =
        match block_data_opt with
        | Some {CModule_type.passed_as_noescape_block_to; procname; return_type} ->
            (passed_as_noescape_block_to, procname, Some return_type)
        | _ ->
            (None, CType_decl.CProcname.from_decl ~tenv func_decl, None)
      in
      let ms, body_opt, extra_instrs =
        CType_decl.method_signature_body_of_decl tenv func_decl ?block_return_type
          ~passed_as_noescape_block_to procname
      in
      match body_opt with
      | Some body ->
          (* Only in the case the function declaration has a defined body we create a procdesc *)
          let return_param_typ_opt = ms.CMethodSignature.return_param_typ in
          if CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] captured_vars
          then
            add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body ms
              return_param_typ_opt outer_context_opt extra_instrs
      | None ->
          ()
    with CFrontend_errors.IncorrectAssumption _ -> ()


  let process_method_decl ?(set_objc_accessor_attr = false) ?(is_destructor = false) trans_unit_ctx
      tenv cfg curr_class meth_decl =
    try
      let ms, body_opt, extra_instrs =
        let procname = CType_decl.CProcname.from_decl ~tenv meth_decl in
        CType_decl.method_signature_body_of_decl tenv meth_decl procname
      in
      match body_opt with
      | Some body ->
          let procname = ms.CMethodSignature.name in
          let return_param_typ_opt = ms.CMethodSignature.return_param_typ in
          let ms', procname' =
            if is_destructor then (
              (* For a destructor we create two procedures: a destructor wrapper and an inner destructor *)
              (* A destructor wrapper is called from the outside, i.e. for destructing local variables and fields *)
              (* The destructor wrapper calls the inner destructor which has the actual body *)
              if
                CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv
                  ms [body] []
              then
                add_method trans_unit_ctx tenv cfg curr_class procname body ms return_param_typ_opt
                  None extra_instrs ~is_destructor_wrapper:true ;
              let new_method_name =
                Config.clang_inner_destructor_prefix ^ Procname.get_method procname
              in
              let ms' =
                {ms with name= Procname.objc_cpp_replace_method_name procname new_method_name}
              in
              let procname' = ms'.CMethodSignature.name in
              (ms', procname') )
            else (ms, procname)
          in
          if
            CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv ms'
              [body] []
          then
            add_method trans_unit_ctx tenv cfg curr_class procname' body ms' return_param_typ_opt
              None extra_instrs ~is_destructor_wrapper:false
      | None ->
          if set_objc_accessor_attr then
            ignore
              (CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv
                 ms [] [])
    with CFrontend_errors.IncorrectAssumption _ -> ()


  let process_property_implementation trans_unit_ctx tenv cfg curr_class
      obj_c_property_impl_decl_info =
    let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in
    match CAst_utils.get_decl_opt_with_decl_ref_opt property_decl_opt with
    | Some (ObjCPropertyDecl (_, _, obj_c_property_decl_info)) ->
        let process_accessor pointer =
          match CAst_utils.get_decl_opt_with_decl_ref_opt pointer with
          | Some (ObjCMethodDecl _ as dec) ->
              process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cfg curr_class
                dec
          | _ ->
              ()
        in
        process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_getter_method ;
        process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_setter_method
    | _ ->
        ()


  let process_one_method_decl trans_unit_ctx tenv cfg curr_class dec =
    let open Clang_ast_t in<commit_msg>[frontend] Clean up method creation<commit_after>(*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

open! IStd
module F = Format

(** Translate declarations **)

module L = Logging

module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFrontend = struct
  (** Translates the method/function's body into nodes of the cfg. *)
  let add_method ?(is_destructor_wrapper = false) trans_unit_ctx tenv cfg class_decl_opt procname
      body ms has_return_param outer_context_opt extra_instrs =
    L.(debug Capture Verbose)
      "@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Procname.pp procname ;
    incr CFrontend_config.procedures_attempted ;
    let recover () =
      incr CFrontend_config.procedures_failed ;
      Procname.Hash.remove cfg procname ;
      let method_kind = ms.CMethodSignature.method_kind in
      CMethod_trans.create_external_procdesc trans_unit_ctx cfg procname method_kind None
    in
    let pp_context fmt () =
      F.fprintf fmt "Aborting translation of method '%a' in file '%a'" Procname.pp procname
        SourceFile.pp trans_unit_ctx.CFrontend_config.source_file
    in
    let f () =
      match Procname.Hash.find_opt cfg procname with
      | Some procdesc when Procdesc.is_defined procdesc && not (BiabductionModels.mem procname) ->
          L.(debug Capture Verbose)
            "@\n@\n>>---------- Start translating body of function: '%s' ---------<<@\n@."
            (Procname.to_string procname) ;
          let vars_to_destroy = CScope.Variables.compute_vars_to_destroy_map body in
          let context =
            CContext.create_context trans_unit_ctx tenv cfg procdesc class_decl_opt has_return_param
              outer_context_opt vars_to_destroy
          in
          let start_node = Procdesc.get_start_node procdesc in
          let exit_node = Procdesc.get_exit_node procdesc in
          let meth_body_nodes =
            T.instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper
          in
          Procdesc.node_set_succs procdesc start_node ~normal:meth_body_nodes ~exn:[]
      | _ ->
          ()
    in
    CFrontend_errors.protect ~f ~recover ~pp_context


  let function_decl trans_unit_ctx tenv cfg func_decl block_data_opt =
    try
      let captured_vars, outer_context_opt =
        match block_data_opt with
        | Some {CModule_type.captured_vars; context= outer_context} ->
            (captured_vars, Some outer_context)
        | None ->
            ([], None)
      in
      let passed_as_noescape_block_to, procname, block_return_type =
        match block_data_opt with
        | Some {CModule_type.passed_as_noescape_block_to; procname; return_type} ->
            (passed_as_noescape_block_to, procname, Some return_type)
        | _ ->
            (None, CType_decl.CProcname.from_decl ~tenv func_decl, None)
      in
      let ms, body_opt, extra_instrs =
        CType_decl.method_signature_body_of_decl tenv func_decl ?block_return_type
          ~passed_as_noescape_block_to procname
      in
      match body_opt with
      | Some body ->
          (* Only in the case the function declaration has a defined body we create a procdesc *)
          let return_param_typ_opt = ms.CMethodSignature.return_param_typ in
          if CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] captured_vars
          then
            add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body ms
              return_param_typ_opt outer_context_opt extra_instrs
      | None ->
          ()
    with CFrontend_errors.IncorrectAssumption _ -> ()


  let process_method_decl ?(set_objc_accessor_attr = false) ?(is_destructor = false) trans_unit_ctx
      tenv cfg curr_class meth_decl =
    try
      let ms, body_opt, extra_instrs =
        let procname = CType_decl.CProcname.from_decl ~tenv meth_decl in
        CType_decl.method_signature_body_of_decl tenv meth_decl procname
      in
      match body_opt with
      | Some body ->
          let procname = ms.CMethodSignature.name in
          let return_param_typ_opt = ms.CMethodSignature.return_param_typ in
          let add_method_if_create_procdesc ms procname ~is_destructor_wrapper =
            if
              CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv ms
                [body] []
            then
              add_method trans_unit_ctx tenv cfg curr_class procname body ms return_param_typ_opt
                None extra_instrs ~is_destructor_wrapper
          in
          ignore (add_method_if_create_procdesc ms procname ~is_destructor_wrapper:is_destructor) ;
          if is_destructor then
            (* For a destructor we create two procedures: a destructor wrapper and an inner destructor *)
            (* A destructor wrapper is called from the outside, i.e. for destructing local variables and fields *)
            (* The destructor wrapper calls the inner destructor which has the actual body *)
            let new_method_name =
              Config.clang_inner_destructor_prefix ^ Procname.get_method procname
            in
            let new_procname = Procname.objc_cpp_replace_method_name procname new_method_name in
            let new_ms = {ms with name= new_procname} in
            add_method_if_create_procdesc new_ms new_procname ~is_destructor_wrapper:false
      | None ->
          if set_objc_accessor_attr then
            ignore
              (CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv
                 ms [] [])
    with CFrontend_errors.IncorrectAssumption _ -> ()


  let process_property_implementation trans_unit_ctx tenv cfg curr_class
      obj_c_property_impl_decl_info =
    let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in
    match CAst_utils.get_decl_opt_with_decl_ref_opt property_decl_opt with
    | Some (ObjCPropertyDecl (_, _, obj_c_property_decl_info)) ->
        let process_accessor pointer =
          match CAst_utils.get_decl_opt_with_decl_ref_opt pointer with
          | Some (ObjCMethodDecl _ as dec) ->
              process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cfg curr_class
                dec
          | _ ->
              ()
        in
        process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_getter_method ;
        process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_setter_method
    | _ ->
        ()


  let process_one_method_decl trans_unit_ctx tenv cfg curr_class dec =
    let open Clang_ast_t in
{'fraction_non_alphanumeric': 0.06126351401044348, 'fraction_numerical': 0.0, 'mean_word_length': 2.6242004264392325, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2342989', 'n_tokens_mistral': 4138, 'n_tokens_neox': 4076, 'n_words': 1014}