diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 7fee729e2..2287fefd2 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -714,12 +714,6 @@ and continue = "Continue the capture for the reactive analysis, increasing the changed files/procedures. (If \ a procedure was changed beforehand, keep the changed marking.)" -and linters_ignore_clang_failures = - CLOpt.mk_bool ~long:"linters-ignore-clang-failures" - ~parse_mode:CLOpt.(Infer [Clang]) - ~default:false - "Continue linting files even if some compilation fails." - and copy_propagation = CLOpt.mk_bool ~deprecated:["copy-propagation"] ~long:"copy-propagation" "Perform copy-propagation on the IR" @@ -734,9 +728,13 @@ and ( developer_mode, debug, debug_exceptions, + default_linters, + failures_allowed, filtering, frontend_tests, + linters_developer_mode, print_buckets, + print_logs, print_types, reports_include_ml_loc, test, @@ -744,7 +742,11 @@ and ( write_html, write_dotty ) = - let developer_mode = + let failures_allowed = + CLOpt.mk_bool ~deprecated_no:["-no_failures_allowed"] ~long:"failures-allowed" ~default:true + "Fail if at least one of the translations fails (clang only)" + + and developer_mode = CLOpt.mk_bool ~long:"developer-mode" ~default:(equal_exe current_exe Print) "Show internal exceptions" @@ -801,19 +803,39 @@ and ( [developer_mode; print_buckets; reports_include_ml_loc] [filtering] + and default_linters = + CLOpt.mk_bool ~long:"default-linters" ~parse_mode:CLOpt.(Infer [Clang]) ~default:true + "Use the default linters for the analysis." + and frontend_tests = CLOpt.mk_bool_group ~long:"frontend-tests" ~parse_mode:CLOpt.(Infer [Clang]) "Save filename.ext.test.dot with the cfg in dotty format for frontend tests (also sets \ --print-types)" [print_types] [] + + and print_logs = + CLOpt.mk_bool ~long:"print-logs" ~parse_mode:CLOpt.(Infer [Driver]) + "Also log messages to stdout and stderr" + in + let linters_developer_mode = + CLOpt.mk_bool_group ~long:"linters-developer-mode" ~parse_mode:CLOpt.(Infer [Clang]) + "Debug mode for developing new linters. (Sets the analyzer to \"linters\"; also sets \ + --debug, --developer-mode, --print-logs, and \ + unsets --allowed-failures and --default-linters." + [debug; developer_mode; print_logs] [failures_allowed; default_linters] + in ( developer_mode, debug, debug_exceptions, + default_linters, + failures_allowed, filtering, frontend_tests, + linters_developer_mode, print_buckets, + print_logs, print_types, reports_include_ml_loc, test, @@ -822,10 +844,6 @@ and ( write_dotty ) -and default_linters = - CLOpt.mk_bool ~long:"default-linters" ~parse_mode:CLOpt.(Infer [Clang]) ~default:true - "Use the default linters for the analysis." - and dependencies = CLOpt.mk_bool ~deprecated:["dependencies"] ~long:"dependencies" ~parse_mode:CLOpt.(Infer [Java]) @@ -900,10 +918,6 @@ and fail_on_bug = (Printf.sprintf "Exit with error code %d if Infer found something to report" fail_on_issue_exit_code) -and failures_allowed = - CLOpt.mk_bool ~deprecated_no:["-no_failures_allowed"] ~long:"failures-allowed" ~default:true - "Fail if at least one of the translations fails (clang only)" - and fcp_apple_clang = CLOpt.mk_path_opt ~long:"fcp-apple-clang" ~meta:"path" "Specify the path to Apple Clang" @@ -1013,15 +1027,21 @@ and latex = ~meta:"file" "Write a latex report of the analysis results to a file" +and linter = + CLOpt.mk_string_opt ~long:"linter" ~parse_mode:CLOpt.(Infer [Clang]) + "From the linters available, only run this one linter. \ + (Useful together with --linters-developer-mode)" + and linters_def_file = CLOpt.mk_path_list ~default:[] ~long:"linters-def-file" ~parse_mode:CLOpt.(Infer [Clang]) ~meta:"file" "Specify the file containing linters definition (e.g. 'linters.al')" -and linters_developer_mode = - CLOpt.mk_bool ~long:"linters-developer-mode" ~parse_mode:CLOpt.(Infer [Clang]) - "Debug mode for developing new linters. Sets the linters analyzer, disables other \ - default linters and also sets --print-logs, --debug and --no-allowed-failures." +and linters_ignore_clang_failures = + CLOpt.mk_bool ~long:"linters-ignore-clang-failures" + ~parse_mode:CLOpt.(Infer [Clang]) + ~default:false + "Continue linting files even if some compilation fails." and load_average = CLOpt.mk_float_opt ~long:"load-average" ~short:'l' @@ -1121,10 +1141,6 @@ and precondition_stats = CLOpt.mk_bool ~deprecated:["precondition_stats"] ~long:"precondition-stats" "Print stats about preconditions to standard output" -and print_logs = - CLOpt.mk_bool ~long:"print-logs" ~parse_mode:CLOpt.(Infer [Driver]) - "Also log messages to stdout and stderr" - and print_builtins = CLOpt.mk_bool ~deprecated:["print_builtins"] ~long:"print-builtins" "Print the builtin functions and exit" @@ -1536,13 +1552,9 @@ let post_parsing_initialization () = List.rev_map ~f:(fun x -> `Raw x) !compilation_database |> List.rev_map_append ~f:(fun x -> `Escaped x) !compilation_database_escaped; - (* set linters developer flags *) + (* set analyzer mode to linters in linters developer mode *) if !linters_developer_mode then ( - debug := true; - failures_allowed := false; - print_logs := true; analyzer := Some Linters; - default_linters := false ); if !default_linters then linters_def_file := linters_def_default_file :: !linters_def_file; @@ -1615,6 +1627,7 @@ and classpath = !classpath and cluster_cmdline = !cluster and compute_analytics = !compute_analytics and continue_capture = !continue +and linter = !linter and default_linters = !default_linters and linters_ignore_clang_failures = !linters_ignore_clang_failures and copy_propagation = !copy_propagation @@ -1664,6 +1677,7 @@ and jobs = !jobs and join_cond = !join_cond and latex = !latex and linters_def_file = !linters_def_file +and linters_developer_mode = !linters_developer_mode and load_average = match !load_average with | None when !buck -> Some (float_of_int ncpu) diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 719ad00bd..10e5712e4 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -270,7 +270,9 @@ val javac_verbose_out : string val jobs : int val join_cond : int val latex : string option +val linter : string option val linters_def_file : string list +val linters_developer_mode : bool val load_analysis_results : string option val makefile_cmdline : string val maven : bool diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index f93162cee..d0161fbd1 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -254,9 +254,12 @@ let store_issues source_file = let do_frontend_checks trans_unit_ctx ast = try let parsed_linters = parse_ctl_files Config.linters_def_file in - CFrontend_errors.parsed_linters := parsed_linters; + let filtered_parsed_linters = CFrontend_errors.filter_parsed_linters parsed_linters in + CFrontend_errors.parsed_linters := filtered_parsed_linters; let source_file = trans_unit_ctx.CFrontend_config.source_file in - Logging.out "Start linting file %a@\n" SourceFile.pp source_file; + Logging.out "Start linting file %a with rules: @\n%s@\n" + SourceFile.pp source_file + (CFrontend_errors.linters_to_string filtered_parsed_linters); match ast with | Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> let context = diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index e74fddfce..8fbac98ac 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -17,6 +17,25 @@ type linter = { def_file : string option; } +(* If in linter developer mode and if current linter was passed, filter it out *) +let filter_parsed_linters parsed_linters = + if List.length parsed_linters > 1 && Config.linters_developer_mode then + match Config.linter with + | None -> + failwith ("ERROR: In linters developer mode you should debug only one linter at a time. \ + This is important for debugging the rule. Pass the flag \ + --linter to specify the linter you want to debug."); + | Some lint -> + List.filter ~f:( + fun (rule : linter) -> String.equal rule.issue_desc.name lint + ) parsed_linters + else parsed_linters + +let linters_to_string linters = + let linter_to_string linters = + List.map ~f:(fun (rule : linter) -> rule.issue_desc.name) linters in + String.concat ~sep:"\n" (linter_to_string linters) + (* Map a formula id to a triple (visited, parameters, definition). Visited is used during the expansion phase to understand if the formula was already expanded and, if yes we have a cyclic definifion *) diff --git a/infer/src/clang/cFrontend_errors.mli b/infer/src/clang/cFrontend_errors.mli index 5b9738a61..f16ee4198 100644 --- a/infer/src/clang/cFrontend_errors.mli +++ b/infer/src/clang/cFrontend_errors.mli @@ -15,6 +15,10 @@ type linter = { def_file : string option; } +val filter_parsed_linters : linter list -> linter list + +val linters_to_string : linter list -> string + (* map used to expand macro. It maps a formula id to a triple (visited, parameters, definition). Visited is used during the expansion phase to understand if the