diff --git a/infer/src/backend/config.ml b/infer/src/backend/config.ml index 9b5b86543..d5e6cdb52 100644 --- a/infer/src/backend/config.ml +++ b/infer/src/backend/config.ml @@ -127,6 +127,8 @@ let inferconfig_file = ".inferconfig" let ivar_attributes = "ivar_attributes" +let linters_mode_enabled = false + (** letters used in the analysis output *) let log_analysis_file = "F" let log_analysis_procedure = "." diff --git a/infer/src/backend/config.mli b/infer/src/backend/config.mli index afe0442f7..7647689d9 100644 --- a/infer/src/backend/config.mli +++ b/infer/src/backend/config.mli @@ -79,6 +79,7 @@ val idempotent_getters : bool val incremental_procs : bool val initial_analysis_time : float val ivar_attributes : string +val linters_mode_enabled : bool val load_average : float option val log_analysis_crash : string val log_analysis_file : string diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 7e114933d..c38e691f4 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -102,7 +102,7 @@ struct let field_name = General_utils.mk_class_field_name named_decl_info in let process_accessor pointer ~getter = (match Ast_utils.get_decl_opt_with_decl_ref pointer with - | Some ObjCMethodDecl (decl_info, name_info, mdi) -> + | Some (ObjCMethodDecl (decl_info, _, _) as d) -> let source_range = decl_info.Clang_ast_t.di_source_range in let loc = CLocation.get_sil_location_from_range source_range true in let property_accessor = @@ -110,8 +110,7 @@ struct Some (ProcAttributes.Objc_getter field_name) else Some (ProcAttributes.Objc_setter field_name) in - let class_name = Ast_utils.get_class_name_from_member name_info in - let procname = CMethod_trans.get_objc_method_name name_info mdi class_name in + let procname = General_utils.procname_of_decl d in let attrs = { (ProcAttributes.default procname Config.Clang) with loc = loc; objc_accessor = property_accessor; } in diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index 165feafc1..0d2917865 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -47,12 +47,26 @@ let global_var_checker_list = [CFrontend_checkers.global_var_init_with_calls_war let checker_for_global_var dec checker = checker dec +let errLogMap = ref Procname.Map.empty + +let get_err_log cfg cg method_decl_opt loc = + if Config.linters_mode_enabled then + let procname = match method_decl_opt with + | Some method_decl -> General_utils.procname_of_decl method_decl + | None -> General_utils.get_procname_for_frontend_checks loc in + try Procname.Map.find procname !errLogMap + with Not_found -> + let errlog = Errlog.empty () in + errLogMap := Procname.Map.add procname errlog !errLogMap; errlog + else + let pdesc = CMethod_trans.get_method_for_frontend_checks cfg cg loc in + Cfg.Procdesc.get_err_log pdesc + (* Add a frontend warning with a description desc at location loc to the errlog of a proc desc *) -let log_frontend_issue cfg cg issue_desc = +let log_frontend_issue cfg cg method_decl_opt issue_desc = let issue = issue_desc.CIssue.issue in let loc = issue_desc.CIssue.loc in - let pdesc = CMethod_trans.get_method_for_frontend_checks cfg cg loc in - let errlog = Cfg.Procdesc.get_err_log pdesc in + let errlog = get_err_log cfg cg method_decl_opt loc in let err_desc = Errdesc.explain_frontend_warning issue_desc.CIssue.description issue_desc.CIssue.suggestion loc in let name = CIssue.to_string issue in @@ -70,10 +84,10 @@ let log_frontend_issue cfg cg issue_desc = 1. f a particular way to apply a checker, it's a partial function 2. context 3. the list of checkers to be applied *) -let invoke_set_of_checkers f cfg cg checkers = +let invoke_set_of_checkers f cfg cg method_decl_opt checkers = IList.iter (fun checker -> match f checker with - | Some issue_desc -> log_frontend_issue cfg cg issue_desc + | Some issue_desc -> log_frontend_issue cfg cg method_decl_opt issue_desc | None -> ()) checkers (* Call all checkers on properties of class c *) @@ -81,7 +95,7 @@ let rec check_for_property_errors cfg cg decl_list = let open Clang_ast_t in let do_one_property decl_info pname_info pdi = let call_property_checker = checkers_for_property decl_info pname_info pdi in - invoke_set_of_checkers call_property_checker cfg cg property_checkers_list in + invoke_set_of_checkers call_property_checker cfg cg None property_checkers_list in match decl_list with | [] -> () | ObjCPropertyDecl (decl_info, pname_info, pdi) :: rest -> @@ -102,11 +116,13 @@ let run_frontend_checkers_on_stmt cfg cg method_decl instr = | ObjCIvarRefExpr(stmt_info, _, _, obj_c_ivar_ref_expr_info) -> let dr_ref = obj_c_ivar_ref_expr_info.Clang_ast_t.ovrei_decl_ref in let call_checker_for_ivar = checkers_for_ivar method_decl stmt_info dr_ref in - invoke_set_of_checkers call_checker_for_ivar cfg cg ivar_access_checker_list + let method_decl_opt = Some method_decl in + invoke_set_of_checkers call_checker_for_ivar cfg cg method_decl_opt ivar_access_checker_list | BlockExpr(stmt_info, _ , _, Clang_ast_t.BlockDecl (_, block_decl_info)) -> let captured_block_vars = block_decl_info.Clang_ast_t.bdi_captured_variables in let call_captured_vars_checker = checkers_for_capture_vars stmt_info captured_block_vars in - invoke_set_of_checkers call_captured_vars_checker cfg cg captured_vars_checker_list + let decl_opt = Some method_decl in + invoke_set_of_checkers call_captured_vars_checker cfg cg decl_opt captured_vars_checker_list | _ -> () let rec run_frontend_checkers_on_decl cfg cg dec = @@ -122,14 +138,14 @@ let rec run_frontend_checkers_on_decl cfg cg dec = let decls = (get_categories_decls idi.Clang_ast_t.oidi_class_interface) @ decl_list in check_for_property_errors cfg cg decls; let call_ns_checker = checkers_for_ns decl_info decl_list in - invoke_set_of_checkers call_ns_checker cfg cg ns_notification_checker_list; + invoke_set_of_checkers call_ns_checker cfg cg None ns_notification_checker_list; IList.iter (run_frontend_checkers_on_decl cfg cg) decl_list | ObjCProtocolDecl (decl_info, _, decl_list, _, _) -> check_for_property_errors cfg cg decl_list; let call_ns_checker = checkers_for_ns decl_info decl_list in - invoke_set_of_checkers call_ns_checker cfg cg ns_notification_checker_list; + invoke_set_of_checkers call_ns_checker cfg cg None ns_notification_checker_list; IList.iter (run_frontend_checkers_on_decl cfg cg) decl_list | VarDecl _ -> let call_global_checker = checker_for_global_var dec in - invoke_set_of_checkers call_global_checker cfg cg global_var_checker_list + invoke_set_of_checkers call_global_checker cfg cg None global_var_checker_list | _ -> () diff --git a/infer/src/clang/cFrontend_errors.mli b/infer/src/clang/cFrontend_errors.mli index 47c94dcd6..d3ed8970c 100644 --- a/infer/src/clang/cFrontend_errors.mli +++ b/infer/src/clang/cFrontend_errors.mli @@ -18,3 +18,4 @@ val run_frontend_checkers_on_stmt : Cfg.cfg -> Cg.t -> Clang_ast_t.decl -> Clang (* Run frontend checkers on a declaration *) val run_frontend_checkers_on_decl : Cfg.cfg -> Cg.t -> Clang_ast_t.decl -> unit +val errLogMap : Errlog.t Procname.Map.t ref diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 6aa965063..4ff5746d0 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -640,6 +640,34 @@ struct Procname.ObjC_Cpp (Procname.objc_cpp class_name method_name mangled_opt) + let get_objc_method_name name_info mdi class_name = + let method_name = name_info.Clang_ast_t.ni_name in + let is_instance = mdi.Clang_ast_t.omdi_is_instance_method in + let method_kind = Procname.objc_method_kind_of_bool is_instance in + mk_procname_from_objc_method class_name method_name method_kind + + let procname_of_decl meth_decl = + let open Clang_ast_t in + match meth_decl with + | FunctionDecl (decl_info, name_info, _, fdi) -> + let name = Ast_utils.get_qualified_name name_info in + let language = Config.clang_lang in + let function_info = Some (decl_info, fdi) in + mk_procname_from_function name function_info language + | CXXMethodDecl (_, name_info, _, fdi, mdi) + | CXXConstructorDecl (_, name_info, _, fdi, mdi) + | CXXConversionDecl (_, name_info, _, fdi, mdi) + | CXXDestructorDecl (_, name_info, _, fdi, mdi) -> + let mangled = get_mangled_method_name fdi mdi in + let method_name = Ast_utils.get_unqualified_name name_info in + let class_name = Ast_utils.get_class_name_from_member name_info in + mk_procname_from_cpp_method class_name method_name mangled + | ObjCMethodDecl (_, name_info, mdi) -> + let class_name = Ast_utils.get_class_name_from_member name_info in + get_objc_method_name name_info mdi class_name + | _ -> assert false + + let get_var_name_mangled name_info var_decl_info = let clang_name = Ast_utils.get_qualified_name name_info in let param_idx_opt = var_decl_info.Clang_ast_t.vdi_parm_index_in_function in @@ -675,4 +703,8 @@ struct Pvar.mk mangled_name procname | None -> Pvar.mk (Mangled.from_string name_string) procname + let get_procname_for_frontend_checks loc = + let mangled = string_crc_hex32 (DB.source_file_to_string loc.Location.file) in + Procname.from_string_c_fun ("frontend_checks_" ^ mangled) + end diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 3a4e3eb62..eaaddc38e 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -209,6 +209,10 @@ sig val mk_procname_from_cpp_method : string -> string -> string option-> Procname.t + val procname_of_decl : Clang_ast_t.decl -> Procname.t + + val get_procname_for_frontend_checks : Location.t -> Procname.t + val mk_class_field_name : Clang_ast_t.named_decl_info -> Ident.fieldname val get_var_name_mangled : Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index d6ff9fa9a..5039a139c 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -156,32 +156,21 @@ let get_init_list_instrs method_decl_info = let create_custom_instr construct_instr = `CXXConstructorInit construct_instr in IList.map create_custom_instr method_decl_info.Clang_ast_t.xmdi_cxx_ctor_initializers -let get_objc_method_name name_info mdi class_name = - let method_name = name_info.Clang_ast_t.ni_name in - let is_instance = mdi.Clang_ast_t.omdi_is_instance_method in - let method_kind = Procname.objc_method_kind_of_bool is_instance in - General_utils.mk_procname_from_objc_method class_name method_name method_kind - let method_signature_of_decl tenv meth_decl block_data_opt = let open Clang_ast_t in match meth_decl, block_data_opt with - | FunctionDecl (decl_info, name_info, tp, fdi), _ -> - let name = Ast_utils.get_qualified_name name_info in + | FunctionDecl (decl_info, _, tp, fdi), _ -> let language = Config.clang_lang in let func_decl = Func_decl_info (fdi, tp, language) in - let function_info = Some (decl_info, fdi) in - let procname = General_utils.mk_procname_from_function name function_info language in + let procname = General_utils.procname_of_decl meth_decl in let ms = build_method_signature tenv decl_info procname func_decl None None in let extra_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in ms, fdi.Clang_ast_t.fdi_body, extra_instrs - | CXXMethodDecl (decl_info, name_info, tp, fdi, mdi), _ - | CXXConstructorDecl (decl_info, name_info, tp, fdi, mdi), _ - | CXXConversionDecl (decl_info, name_info, tp, fdi, mdi), _ - | CXXDestructorDecl (decl_info, name_info, tp, fdi, mdi), _ -> - let method_name = Ast_utils.get_unqualified_name name_info in - let class_name = Ast_utils.get_class_name_from_member name_info in - let mangled = General_utils.get_mangled_method_name fdi mdi in - let procname = General_utils.mk_procname_from_cpp_method class_name method_name mangled in + | CXXMethodDecl (decl_info, _, tp, fdi, mdi), _ + | CXXConstructorDecl (decl_info, _, tp, fdi, mdi), _ + | CXXConversionDecl (decl_info, _, tp, fdi, mdi), _ + | CXXDestructorDecl (decl_info, _, tp, fdi, mdi), _ -> + let procname = General_utils.procname_of_decl meth_decl in let parent_ptr = Option.get decl_info.di_parent_pointer in let method_decl = Cpp_Meth_decl_info (fdi, mdi, parent_ptr, tp) in let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in @@ -189,9 +178,8 @@ let method_signature_of_decl tenv meth_decl block_data_opt = let non_null_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in let init_list_instrs = get_init_list_instrs mdi in (* it will be empty for methods *) ms, fdi.Clang_ast_t.fdi_body, (init_list_instrs @ non_null_instrs) - | ObjCMethodDecl (decl_info, name_info, mdi), _ -> - let class_name = Ast_utils.get_class_name_from_member name_info in - let procname = get_objc_method_name name_info mdi class_name in + | ObjCMethodDecl (decl_info, _, mdi), _ -> + let procname = General_utils.procname_of_decl meth_decl in let parent_ptr = Option.get decl_info.di_parent_pointer in let method_decl = ObjC_Meth_decl_info (mdi, parent_ptr) in let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in @@ -451,8 +439,7 @@ let create_procdesc_with_pointer context pointer class_name_opt name = callee_name let get_method_for_frontend_checks cfg cg loc = - let mangled = string_crc_hex32 (DB.source_file_to_string loc.Location.file) in - let proc_name = Procname.from_string_c_fun ("frontend_checks_" ^ mangled) in + let proc_name = General_utils.get_procname_for_frontend_checks loc in match Cfg.Procdesc.find_from_name cfg proc_name with | Some pdesc -> pdesc | None -> diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 1df395255..f1ac02bed 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -55,6 +55,3 @@ val get_method_for_frontend_checks : Cfg.cfg -> Cg.t -> Location.t -> Cfg.Procde val add_default_method_for_class : string -> Clang_ast_t.decl_info -> unit val get_procname_from_cpp_lambda : CContext.t -> Clang_ast_t.decl -> Procname.t - -val get_objc_method_name : Clang_ast_t.named_decl_info -> Clang_ast_t.obj_c_method_decl_info -> - string -> Procname.t