From cdd58da8b1260cf33721a01c693c309c4703da16 Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Fri, 10 Mar 2017 08:39:30 -0800 Subject: [PATCH] [linters] Save the linters file in the linter definition Reviewed By: ddino Differential Revision: D4689093 fbshipit-source-id: bd4e706 --- infer/src/clang/cFrontend_checkers_main.ml | 40 ++++++++++++---------- infer/src/clang/cFrontend_errors.ml | 37 ++++++++++++-------- infer/src/clang/cFrontend_errors.mli | 11 ++++-- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index a1e820c17..13076ffc9 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -11,9 +11,7 @@ open! IStd open Lexing open Ctl_lexer -(* Parse the file with linters definitions, and it returns a list - of checkers in the form of pairs (condition, issue_desc) *) -let parse_ctl_file linters_files = +let parse_ctl_file linters_def_file channel : CFrontend_errors.linter list = let print_position _ lexbuf = let pos = lexbuf.lex_curr_p in Logging.err "%s:%d:%d" pos.pos_fname @@ -29,21 +27,26 @@ let parse_ctl_file linters_files = \n########################################################\n@." print_position lexbuf; exit (-1) in - List.iter ~f:(fun fn -> - Logging.out "Loading linters rules from %s\n" fn; - let inx = open_in fn in - let lexbuf = Lexing.from_channel inx in - lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = fn }; - (match parse_with_error lexbuf with - | Some parsed_checkers -> - Logging.out "#### Start Expanding checkers #####\n"; - let exp_checkers = CFrontend_errors.expand_checkers parsed_checkers in - Logging.out "#### Checkers Expanded #####\n"; - if Config.debug_mode then List.iter ~f:CTL.print_checker exp_checkers; - CFrontend_errors.make_condition_issue_desc_pair exp_checkers; - | None -> Logging.out "No linters found.\n"); - In_channel.close inx) linters_files + let lexbuf = Lexing.from_channel channel in + lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = linters_def_file }; + match parse_with_error lexbuf with + | Some parsed_checkers -> + Logging.out "#### Start Expanding checkers #####\n"; + let exp_checkers = CFrontend_errors.expand_checkers parsed_checkers in + Logging.out "#### Checkers Expanded #####\n"; + if Config.debug_mode then List.iter ~f:CTL.print_checker exp_checkers; + CFrontend_errors.create_parsed_linters linters_def_file exp_checkers + | None -> Logging.out "No linters found.\n";[] +(* Parse the files with linters definitions, and it returns a list of linters *) +let parse_ctl_files linters_def_files : CFrontend_errors.linter list = + let collect_parsed_linters linters_def_file linters = + Logging.out "Loading linters rules from %s\n" linters_def_file; + let in_channel = open_in linters_def_file in + let parsed_linters = parse_ctl_file linters_def_file in_channel in + In_channel.close in_channel; + List.append parsed_linters linters in + List.fold_right ~f:collect_parsed_linters ~init:[] linters_def_files let rec get_responds_to_selector stmt = let open Clang_ast_t in @@ -209,7 +212,8 @@ let store_issues source_file = let do_frontend_checks trans_unit_ctx ast = try - parse_ctl_file Config.linters_def_file; + let parsed_linters = parse_ctl_files Config.linters_def_file in + CFrontend_errors.parsed_linters := parsed_linters; let source_file = trans_unit_ctx.CFrontend_config.source_file in Logging.out "Start linting file %a@\n" SourceFile.pp source_file; match ast with diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index 17904674c..aabd44828 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -9,6 +9,12 @@ open! IStd +type linter = { + condition : CTL.t; + issue_desc : CIssue.issue_desc; + def_file : string option; +} + let single_to_multi checker = fun ctx an -> let condition, issue_desc_opt = checker ctx an in @@ -35,8 +41,9 @@ let stmt_single_checkers_list = let stmt_checkers_list = List.map ~f:single_to_multi stmt_single_checkers_list -(* List of checkers that will be filled after parsing them from a file *) -let checkers_decl_stmt = ref [] +(* List of checkers that will be filled after parsing them from + input the linter def files *) +let parsed_linters = ref [] let evaluate_place_holder ph an = match ph with @@ -92,8 +99,8 @@ let string_to_issue_mode m = (Logging.err "\n[ERROR] Mode %s does not exist. Please specify ON/OFF\n" s; assert false) -(** Convert a parsed checker in a pair (condition, issue_desc) *) -let make_condition_issue_desc_pair checkers = +(** Convert a parsed checker in list of linters *) +let create_parsed_linters linters_def_file checkers : linter list = let open CIssue in let open CTL in let open Ctl_parser_types in @@ -107,7 +114,7 @@ let make_condition_issue_desc_pair checkers = severity = Exceptions.Kwarning; mode = CIssue.On; } in - let issue, condition = List.fold ~f:(fun (issue', cond') d -> + let issue_desc, condition = List.fold ~f:(fun (issue', cond') d -> match d with | CSet (s, phi) when String.equal s report_when_const -> issue', phi @@ -124,9 +131,9 @@ let make_condition_issue_desc_pair checkers = Logging.out "\nMaking condition and issue desc for checker '%s'\n" c.name; Logging.out "\nCondition =\n %a\n" CTL.Debug.pp_formula condition; - Logging.out "\nIssue_desc = %a\n" CIssue.pp_issue issue); - condition, issue in - checkers_decl_stmt := List.map ~f:do_one_checker checkers + Logging.out "\nIssue_desc = %a\n" CIssue.pp_issue issue_desc); + {condition; issue_desc; def_file = Some linters_def_file} in + List.map ~f:do_one_checker checkers (* expands use of let defined formula id in checkers with their definition *) @@ -232,18 +239,18 @@ let invoke_set_of_hard_coded_checkers_an context (an : Ctl_parser_types.ast_node ) checkers (* Calls the set of checkers parsed from files (if any) *) -let invoke_set_of_parsed_checkers_an context (an : Ctl_parser_types.ast_node) = +let invoke_set_of_parsed_checkers_an parsed_linters context (an : Ctl_parser_types.ast_node) = let key = match an with | Decl dec -> CAst_utils.generate_key_decl dec | Stmt st -> CAst_utils.generate_key_stmt st in - List.iter ~f:(fun (condition, issue_desc) -> - if CIssue.should_run_check issue_desc.CIssue.mode && - CTL.eval_formula condition an context then + List.iter ~f:(fun (linter : linter) -> + if CIssue.should_run_check linter.issue_desc.CIssue.mode && + CTL.eval_formula linter.condition an context then let loc = CFrontend_checkers.location_from_an context an in - fill_issue_desc_info_and_log context an key issue_desc loc - ) !checkers_decl_stmt + fill_issue_desc_info_and_log context an key linter.issue_desc loc + ) parsed_linters (* We decouple the hardcoded checkers from the parsed ones *) let invoke_set_of_checkers_on_node context an = - invoke_set_of_parsed_checkers_an context an; + invoke_set_of_parsed_checkers_an !parsed_linters context an; invoke_set_of_hard_coded_checkers_an context an diff --git a/infer/src/clang/cFrontend_errors.mli b/infer/src/clang/cFrontend_errors.mli index 6401158df..6d00a798a 100644 --- a/infer/src/clang/cFrontend_errors.mli +++ b/infer/src/clang/cFrontend_errors.mli @@ -9,6 +9,14 @@ open! IStd +type linter = { + condition : CTL.t; + issue_desc : CIssue.issue_desc; + def_file : string option; +} + +(* List of checkers that will be filled after parsing them from a file *) +val parsed_linters : linter list ref (* Module for warnings detected at translation time by the frontend *) @@ -17,7 +25,6 @@ val invoke_set_of_checkers_on_node : CLintersContext.context -> Ctl_parser_types val expand_checkers : CTL.ctl_checker list -> CTL.ctl_checker list -val make_condition_issue_desc_pair : - CTL.ctl_checker list -> unit +val create_parsed_linters : string -> CTL.ctl_checker list -> linter list val remove_new_lines : string -> string