diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index b6fdf003b..d2ec49aa7 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -178,7 +178,8 @@ let make_next_object_exp stmt_info item items = let decl_ref_expr_info = make_decl_ref_expr_info decl_ref in (Clang_ast_t.DeclRefExpr (stmt_info_var, [], expr_info, decl_ref_expr_info), var_qual_type) | _ -> - CFrontend_config.incorrect_assumption "unexpected item %a" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None + "unexpected item %a" (Pp.to_string ~f:Clang_ast_j.string_of_stmt) item in diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 44573b1a3..8cc5544cd 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -20,15 +20,22 @@ let string_of_clang_lang (lang: clang_lang) : string = let equal_clang_lang = [%compare.equal : clang_lang] -exception IncorrectAssumption of string +type exception_details = + { msg: string + ; position: string * int * int * int + ; source_range: Clang_ast_t.source_range + ; ast_node: string option } -let incorrect_assumption fmt = F.kasprintf (fun msg -> raise (IncorrectAssumption msg)) fmt +exception Unimplemented of exception_details -exception Unimplemented of - string * (string * int * int * int) * Clang_ast_t.source_range * string option +let unimplemented position source_range ast_node fmt = + F.kasprintf (fun msg -> raise (Unimplemented {msg; position; source_range; ast_node})) fmt -let unimplemented pos source_range ast_node fmt = - F.kasprintf (fun msg -> raise (Unimplemented (msg, pos, source_range, ast_node))) fmt + +exception IncorrectAssumption of exception_details + +let incorrect_assumption position source_range ast_node fmt = + F.kasprintf (fun msg -> raise (IncorrectAssumption {msg; position; source_range; ast_node})) fmt type translation_unit_context = {lang: clang_lang; source_file: SourceFile.t} diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index d7788ea1a..0df1c095e 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -17,14 +17,13 @@ val string_of_clang_lang : clang_lang -> string val equal_clang_lang : clang_lang -> clang_lang -> bool -exception IncorrectAssumption of string +type exception_details = + { msg: string + ; position: string * int * int * int + ; source_range: Clang_ast_t.source_range + ; ast_node: string option } -val incorrect_assumption : ('a, Format.formatter, unit, _) format4 -> 'a -(** Used to mark places in the frontend that incorrectly assume something to be - impossible. TODO(t21762295) get rid of all instances of this. *) - -exception Unimplemented of - string * (string * int * int * int) * Clang_ast_t.source_range * string option +exception Unimplemented of exception_details val unimplemented : string * int * int * int -> Clang_ast_t.source_range -> string option @@ -32,6 +31,14 @@ val unimplemented : (** Raise Unimplemented. This is caught at the level of translating a method and makes the frontend give up on that method. *) +exception IncorrectAssumption of exception_details + +val incorrect_assumption : + string * int * int * int -> Clang_ast_t.source_range -> string option + -> ('a, Format.formatter, unit, _) format4 -> 'a +(** Used to mark places in the frontend that incorrectly assume something to be + impossible. TODO(t21762295) get rid of all instances of this. *) + type translation_unit_context = {lang: clang_lang; source_file: SourceFile.t} (** Constants *) diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 87a03d39f..f275ffd8f 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -35,15 +35,19 @@ let protect ~f ~recover ~pp_context (trans_unit_ctx: CFrontend_config.translatio (* Always keep going in case of known limitations of the frontend, crash otherwise (by not catching the exception) unless `--keep-going` was passed. Print errors we should fix (t21762295) to the console. *) - | CFrontend_config.Unimplemented (msg, exception_pos, source_range, ast_node) -> + | CFrontend_config.Unimplemented e -> let caught_unimplemented_exception = - caught_exception "Unimplemented" exception_pos source_range ast_node + caught_exception "Unimplemented" e.position e.source_range e.ast_node in EventLogger.log caught_unimplemented_exception ; - log_and_recover ~print:false "Unimplemented feature:@\n %s@\n" msg - | CFrontend_config.IncorrectAssumption msg -> + log_and_recover ~print:false "Unimplemented feature:@\n %s@\n" e.msg + | CFrontend_config.IncorrectAssumption e -> (* FIXME(t21762295): we do not expect this to happen but it does *) - log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" msg + let caught_incorrect_assumption = + caught_exception "IncorrectAssumption" e.position e.source_range e.ast_node + in + EventLogger.log caught_incorrect_assumption ; + log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" e.msg | CTrans_utils.Self.SelfClassException class_name -> (* FIXME(t21762295): we do not expect this to happen but it does *) log_and_recover ~print:true "Unexpected SelfClassException %a@\n" Typ.Name.pp class_name @@ -339,7 +343,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron (* create the corresponding global variable to get the right pname for its initializer *) let global = - CGeneral_utils.mk_sil_global_var trans_unit_ctx named_decl_info vdi qt + CGeneral_utils.mk_sil_global_var trans_unit_ctx decl_info named_decl_info vdi qt in (* safe to Option.get because it's a global *) Option.value_exn (Pvar.get_initializer_pname global) diff --git a/infer/src/clang/cGeneral_utils.ml b/infer/src/clang/cGeneral_utils.ml index 9c635817c..b110b617c 100644 --- a/infer/src/clang/cGeneral_utils.ml +++ b/infer/src/clang/cGeneral_utils.ml @@ -79,7 +79,7 @@ let is_objc_extension translation_unit_context = || CFrontend_config.equal_clang_lang lang CFrontend_config.ObjCPP -let get_var_name_mangled name_info var_decl_info = +let get_var_name_mangled decl_info name_info var_decl_info = let clang_name = CAst_utils.get_qualified_name name_info |> QualifiedCppName.to_qual_string in let param_idx_opt = var_decl_info.Clang_ast_t.vdi_parm_index_in_function in let name_string = @@ -87,7 +87,7 @@ let get_var_name_mangled name_info var_decl_info = | "", Some index -> "__param_" ^ string_of_int index | "", None -> - CFrontend_config.incorrect_assumption + CFrontend_config.incorrect_assumption __POS__ decl_info.Clang_ast_t.di_source_range None "Got both empty clang_name and None for param_idx in get_var_name_mangled (%a) (%a)" (Pp.to_string ~f:Clang_ast_j.string_of_named_decl_info) name_info @@ -106,9 +106,9 @@ let get_var_name_mangled name_info var_decl_info = (name_string, mangled) -let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name= fun _ x -> x) named_decl_info - var_decl_info qt = - let name_string, simple_name = get_var_name_mangled named_decl_info var_decl_info in +let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name= fun _ x -> x) decl_info + named_decl_info var_decl_info qt = + let name_string, simple_name = get_var_name_mangled decl_info named_decl_info var_decl_info in let translation_unit = match Clang_ast_t.(var_decl_info.vdi_is_extern, var_decl_info.vdi_init_expr) with | true, None -> @@ -150,7 +150,9 @@ let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name= fun _ x -> x) na let mk_sil_var trans_unit_ctx named_decl_info decl_info_qual_type_opt procname outer_procname = match decl_info_qual_type_opt with | Some (decl_info, qt, var_decl_info, should_be_mangled) -> - let name_string, simple_name = get_var_name_mangled named_decl_info var_decl_info in + let name_string, simple_name = + get_var_name_mangled decl_info named_decl_info var_decl_info + in if var_decl_info.Clang_ast_t.vdi_is_global then let mk_name = if var_decl_info.Clang_ast_t.vdi_is_static_local then @@ -159,7 +161,7 @@ let mk_sil_var trans_unit_ctx named_decl_info decl_info_qual_type_opt procname o Mangled.from_string (Typ.Procname.to_string outer_procname ^ "_" ^ name_string) ) else None in - mk_sil_global_var trans_unit_ctx ?mk_name named_decl_info var_decl_info qt + mk_sil_global_var trans_unit_ctx ?mk_name decl_info named_decl_info var_decl_info qt else if not should_be_mangled then Pvar.mk simple_name procname else let start_location = fst decl_info.Clang_ast_t.di_source_range in diff --git a/infer/src/clang/cGeneral_utils.mli b/infer/src/clang/cGeneral_utils.mli index 31829b5a6..9a5b2904c 100644 --- a/infer/src/clang/cGeneral_utils.mli +++ b/infer/src/clang/cGeneral_utils.mli @@ -24,11 +24,13 @@ val list_range : int -> int -> int list val mk_class_field_name : Typ.Name.t -> string -> Typ.Fieldname.t val get_var_name_mangled : - Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> string * Mangled.t + Clang_ast_t.decl_info -> Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info + -> string * Mangled.t val mk_sil_global_var : CFrontend_config.translation_unit_context -> ?mk_name:(string -> Mangled.t -> Mangled.t) - -> Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> Clang_ast_t.qual_type -> Pvar.t + -> Clang_ast_t.decl_info -> Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info + -> Clang_ast_t.qual_type -> Pvar.t val mk_sil_var : CFrontend_config.translation_unit_context -> Clang_ast_t.named_decl_info -> var_info option diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index c87cf0e08..7ec2234eb 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -126,11 +126,11 @@ let is_cpp_nothrow function_method_decl_info = 1. self/this parameter (optional, only for methods) 2. normal parameters 3. return parameter (optional) *) -let get_parameters trans_unit_ctx tenv function_method_decl_info = +let get_parameters trans_unit_ctx tenv decl_info function_method_decl_info = let par_to_ms_par par = match par with | Clang_ast_t.ParmVarDecl (_, name_info, qt, var_decl_info) -> - let _, mangled = CGeneral_utils.get_var_name_mangled name_info var_decl_info in + let _, mangled = CGeneral_utils.get_var_name_mangled decl_info name_info var_decl_info in let param_typ = CType_decl.qual_type_to_sil_type tenv qt in let new_qt = match param_typ.Typ.desc with @@ -163,7 +163,7 @@ let build_method_signature trans_unit_ctx tenv decl_info procname function_metho let source_range = decl_info.Clang_ast_t.di_source_range in let tp, return_param_type_opt = get_return_val_and_param_types tenv function_method_decl_info in let is_instance_method = is_instance_method function_method_decl_info in - let parameters = get_parameters trans_unit_ctx tenv function_method_decl_info in + let parameters = get_parameters trans_unit_ctx tenv decl_info function_method_decl_info in let attributes = decl_info.Clang_ast_t.di_attributes in let lang = get_language trans_unit_ctx function_method_decl_info in let is_cpp_virtual = is_cpp_virtual function_method_decl_info in diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 22cf00ac9..a78956e43 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -516,7 +516,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s assert false ) | _ as decl -> (* FIXME(t21762295): we do not expect this to happen but it does *) - CFrontend_config.incorrect_assumption + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None "di_parent_pointer should be always set for fields/ivars, but got %a" (Pp.option (Pp.to_string ~f:Clang_ast_j.string_of_decl)) decl @@ -709,7 +709,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s in let procname = Procdesc.get_proc_name context.procdesc in let sil_loc = CLocation.get_sil_location stmt_info context in - let pvar = CVar_decl.sil_var_of_decl_ref context decl_ref procname in + let pvar = + CVar_decl.sil_var_of_decl_ref context stmt_info.Clang_ast_t.si_source_range decl_ref procname + in CContext.add_block_static_var context procname (pvar, typ) ; let var_exp = Exp.Lvar pvar in let exps = @@ -986,7 +988,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s if Int.equal (List.length params) (List.length params_stmt) then params else (* FIXME(t21762295) this is reachable *) - CFrontend_config.incorrect_assumption + CFrontend_config.incorrect_assumption __POS__ si.Clang_ast_t.si_source_range None "In call to %a: stmt_list and res_trans_par.exps must have same size but they don't:@\nstmt_list(%d)=[%a]@\nres_trans_par.exps(%d)=[%a]@\n" Typ.Procname.pp procname (List.length params) (Pp.seq Exp.pp) (List.map ~f:fst params) (List.length params_stmt) @@ -1024,8 +1026,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s pn | _ -> (* method pointer not implemented, this shouldn't happen but it does (t21762295) *) - CFrontend_config.incorrect_assumption "Could not resolve CXX method call %a" Exp.pp - sil_method + CFrontend_config.incorrect_assumption __POS__ si.Clang_ast_t.si_source_range None + "Could not resolve CXX method call %a" Exp.pp sil_method in (* As we may have nodes coming from different parameters we need to call instruction for each parameter and collect the results afterwards. The 'instructions' function does not do that *) @@ -1852,7 +1854,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s {empty_res_trans with root_nodes= top_nodes; leaf_nodes= succ_nodes} | _ -> (* TODO(t21762295) this raises sometimes *) - CFrontend_config.incorrect_assumption + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None "Unexpected Switch Statement sub-expression list: [%a]" (Pp.semicolon_seq (Pp.to_string ~f:Clang_ast_j.string_of_stmt)) switch_stmt_list @@ -2237,7 +2239,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (* Record declaration is done in the beginning when procdesc is defined.*) collect_all_decl trans_state var_decls' next_nodes stmt_info | decl :: _ -> - CFrontend_config.incorrect_assumption "unexpected decl type %s in collect_all_decl: %a" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None + "unexpected decl type %s in collect_all_decl: %a" (Clang_ast_proj.get_decl_kind_string decl) (Pp.to_string ~f:Clang_ast_j.string_of_decl) decl @@ -2603,7 +2606,10 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (* defining procedure. We add an edge in the call graph.*) Cg.add_edge context.cg procname block_pname ; let captured_block_vars = block_decl_info.Clang_ast_t.bdi_captured_variables in - let captureds = CVar_decl.captured_vars_from_block_info context captured_block_vars in + let captureds = + CVar_decl.captured_vars_from_block_info context stmt_info.Clang_ast_t.si_source_range + captured_block_vars + in let ids_instrs = List.map ~f:assign_captured_var captureds in let ids, instrs = List.unzip ids_instrs in let block_data = (context, qual_type, block_pname, captureds) in @@ -2631,7 +2637,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s Cg.add_edge context.cg procname lambda_pname ; let make_captured_tuple (pvar, typ) = (Exp.Lvar pvar, pvar, typ) in let get_captured_pvar_typ decl_ref = - CVar_decl.sil_var_of_captured_var decl_ref context procname + CVar_decl.sil_var_of_captured_var decl_ref context stmt_info.Clang_ast_t.si_source_range + procname in let translate_capture_init (pvar, typ) init_decl = match init_decl with @@ -2983,7 +2990,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s if destr_trans_result.root_nodes <> [] then destr_trans_result else {empty_res_trans with root_nodes= bn.break} | _ (* t21762295 *) -> - CFrontend_config.incorrect_assumption "Break stmt without continuation: %a" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None + "Break stmt without continuation: %a" (Pp.to_string ~f:Clang_ast_j.string_of_stmt_info) stmt_info @@ -2996,7 +3004,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s if destr_trans_result.root_nodes <> [] then destr_trans_result else {empty_res_trans with root_nodes= bn.continue} | _ (* t21762295 *) -> - CFrontend_config.incorrect_assumption "Continue stmt without continuation: %a" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None + "Continue stmt without continuation: %a" (Pp.to_string ~f:Clang_ast_j.string_of_stmt_info) stmt_info @@ -3052,7 +3061,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s switchStmt_trans trans_state stmt_info switch_stmt_list | CaseStmt _ -> (* where do we even get case stmts outside of the switch stmt? (t21762295) *) - CFrontend_config.incorrect_assumption "Case statement outside of switch statement: %a" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None + "Case statement outside of switch statement: %a" (Pp.to_string ~f:Clang_ast_j.string_of_stmt) instr | StmtExpr (_, stmt_list, _) -> @@ -3240,7 +3250,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (Pp.to_string ~f:Clang_ast_j.string_of_stmt) instr | ForStmt (_, _) | WhileStmt (_, _) | DoStmt (_, _) | ObjCForCollectionStmt (_, _) -> - CFrontend_config.incorrect_assumption "Unexpected shape for %a: %a" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None + "Unexpected shape for %a: %a" (Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string) instr (Pp.to_string ~f:Clang_ast_j.string_of_stmt) diff --git a/infer/src/clang/cVar_decl.ml b/infer/src/clang/cVar_decl.ml index 3616bf175..bacf65cc4 100644 --- a/infer/src/clang/cVar_decl.ml +++ b/infer/src/clang/cVar_decl.ml @@ -34,7 +34,7 @@ let sil_var_of_decl context var_decl procname = assert false -let sil_var_of_decl_ref context decl_ref procname = +let sil_var_of_decl_ref context source_range decl_ref procname = let name = match decl_ref.Clang_ast_t.dr_name with Some name_info -> name_info | None -> assert false in @@ -53,7 +53,7 @@ let sil_var_of_decl_ref context decl_ref procname = sil_var_of_decl context var_decl procname | None -> (* FIXME(t21762295) *) - CFrontend_config.incorrect_assumption + CFrontend_config.incorrect_assumption __POS__ source_range None "pointer '%d' for var decl not found. The var decl was: %a" pointer (Pp.to_string ~f:Clang_ast_j.string_of_decl_ref) decl_ref @@ -80,24 +80,24 @@ let add_var_to_locals procdesc var_decl typ pvar = assert false -let sil_var_of_captured_var decl_ref context procname = +let sil_var_of_captured_var decl_ref context source_range procname = match decl_ref with | {Clang_ast_t.dr_qual_type= Some qual_type} -> - ( sil_var_of_decl_ref context decl_ref procname + ( sil_var_of_decl_ref context source_range decl_ref procname , CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type ) | _ -> assert false (* Returns a list of captured variables as sil variables. *) -let captured_vars_from_block_info context cvl = +let captured_vars_from_block_info context source_range cvl = let procname = Procdesc.get_proc_name context.CContext.procdesc in let sil_var_of_captured_var {Clang_ast_t.bcv_variable} vars_acc = match bcv_variable with | Some ({Clang_ast_t.dr_name= Some {Clang_ast_t.ni_name}} as decl_ref) -> if String.equal ni_name CFrontend_config.self && not (CContext.is_objc_instance context) then vars_acc - else sil_var_of_captured_var decl_ref context procname :: vars_acc + else sil_var_of_captured_var decl_ref context source_range procname :: vars_acc | _ -> assert false in diff --git a/infer/src/clang/cVar_decl.mli b/infer/src/clang/cVar_decl.mli index aeaa9e59c..a1f74051a 100644 --- a/infer/src/clang/cVar_decl.mli +++ b/infer/src/clang/cVar_decl.mli @@ -15,12 +15,15 @@ open! IStd val sil_var_of_decl : CContext.t -> Clang_ast_t.decl -> Typ.Procname.t -> Pvar.t -val sil_var_of_decl_ref : CContext.t -> Clang_ast_t.decl_ref -> Typ.Procname.t -> Pvar.t +val sil_var_of_decl_ref : + CContext.t -> Clang_ast_t.source_range -> Clang_ast_t.decl_ref -> Typ.Procname.t -> Pvar.t val add_var_to_locals : Procdesc.t -> Clang_ast_t.decl -> Typ.t -> Pvar.t -> unit val sil_var_of_captured_var : - Clang_ast_t.decl_ref -> CContext.t -> Typ.Procname.t -> Pvar.t * Typ.typ + Clang_ast_t.decl_ref -> CContext.t -> Clang_ast_t.source_range -> Typ.Procname.t + -> Pvar.t * Typ.typ val captured_vars_from_block_info : - CContext.t -> Clang_ast_t.block_captured_variable list -> (Pvar.t * Typ.t) list + CContext.t -> Clang_ast_t.source_range -> Clang_ast_t.block_captured_variable list + -> (Pvar.t * Typ.t) list