[config] Add first step of generalized filtering system

Summary:
This diff takes the first step toward a more general filtering
system. This step is concerned only with filtering at the reporting
stage, filtering for the capture and analysis stages is left for
later.

This diff adds a new command line / config option
```
       --filter-report +string
           Specify a filter for issues to report. If multiple filters are
           specified, they are applied in the order in which they are
           specified. Each filter is applied to each issue detected, and only
           issues which are accepted by all filters are reported. Each filter
           is of the form:
           `<issue_type_regex>:<filename_regex>:<reason_string>`. The first
           two components are OCaml Str regular expressions, with an optional
           `!` character prefix. If a regex has a `!` prefix, the polarity is
           inverted, and the filter becomes a "blacklist" instead of a
           "whitelist". Each filter is interpreted as an implication: an issue
           matches if it does not match the `issue_type_regex` or if it does
           match the `filename_regex`. The filenames that are tested by the
           regex are relative to the `--project-root` directory. The
           `<reason_string>` is a non-empty string used to explain why the
           issue was filtered.
           See also infer-report(1) and infer-run(1).
```

Reviewed By: jvillard

Differential Revision: D6182486

fbshipit-source-id: 9d3922b
master
Josh Berdine 7 years ago committed by Facebook Github Bot
parent ccd2c76344
commit 15d09ccac8

@ -42,6 +42,7 @@ type jsonbug = {
bug_type_hum: string;
?linters_def_file: string option;
?traceview_id: int option;
censored_reason : string;
}
type report = jsonbug list

@ -247,6 +247,21 @@ let should_report (issue_kind: Exceptions.err_kind) issue_type error_desc eclass
else true
(* The reason an issue should be censored (that is, not reported). The empty
string (that is "no reason") means that the issue should be reported. *)
let censored_reason (issue_type: IssueType.t) source_file =
let filename = SourceFile.to_rel_path source_file in
let rejected_by ((issue_type_polarity, issue_type_re), (filename_polarity, filename_re), reason) =
let accepted =
(* matches issue_type_re implies matches filename_re *)
not (Bool.equal issue_type_polarity (Str.string_match issue_type_re issue_type.unique_id 0))
|| Bool.equal filename_polarity (Str.string_match filename_re filename 0)
in
Option.some_if (not accepted) reason
in
Option.value ~default:"" (List.find_map Config.filter_report ~f:rejected_by)
module IssuesCsv = struct
let csv_issues_id = ref 0
@ -410,7 +425,8 @@ module IssuesJson = struct
; bug_type_hum= key.err_name.IssueType.hum
; linters_def_file= err_data.linters_def_file
; doc_url= err_data.doc_url
; traceview_id= None }
; traceview_id= None
; censored_reason= censored_reason key.err_name source_file }
in
if not !is_first_item then pp "," else is_first_item := false ;
pp "%s@?" (Jsonbug_j.string_of_jsonbug bug)
@ -495,7 +511,9 @@ module IssuesTxt = struct
| None ->
err_data.loc.Location.file
in
if key.in_footprint && error_filter source_file key.err_desc key.err_name then
if key.in_footprint && error_filter source_file key.err_desc key.err_name
&& (not Config.filtering || String.is_empty (censored_reason key.err_name source_file))
then
Exceptions.pp_err ~node_key:err_data.node_id_key.node_key err_data.loc key.err_kind
key.err_name key.err_desc None fmt ()

@ -1275,6 +1275,12 @@ and filter_paths =
CLOpt.mk_bool ~long:"filter-paths" ~default:true "Filters specified in .inferconfig"
and filter_report =
CLOpt.mk_string_list ~long:"filter-report"
~in_help:CLOpt.([(Report, manual_generic); (Run, manual_generic)])
"Specify a filter for issues to report. If multiple filters are specified, they are applied in the order in which they are specified. Each filter is applied to each issue detected, and only issues which are accepted by all filters are reported. Each filter is of the form: `<issue_type_regex>:<filename_regex>:<reason_string>`. The first two components are OCaml Str regular expressions, with an optional `!` character prefix. If a regex has a `!` prefix, the polarity is inverted, and the filter becomes a \"blacklist\" instead of a \"whitelist\". Each filter is interpreted as an implication: an issue matches if it does not match the `issue_type_regex` or if it does match the `filename_regex`. The filenames that are tested by the regex are relative to the `--project-root` directory. The `<reason_string>` is a non-empty string used to explain why the issue was filtered."
and flavors =
CLOpt.mk_bool ~deprecated:["-use-flavors"] ~long:"flavors"
~in_help:CLOpt.([(Capture, manual_buck_flavors)])
@ -2402,6 +2408,21 @@ and file_renamings = !file_renamings
and filter_paths = !filter_paths
and filter_report =
List.map !filter_report ~f:(fun str ->
match String.split str ~on:':' with
| [issue_type_re; filename_re; reason_str]
when not String.(is_empty issue_type_re || is_empty filename_re || is_empty reason_str) ->
let polarity_regex re =
let polarity = not (Char.equal '!' re.[0]) in
let regex = Str.regexp (if polarity then re else String.slice re 1 0) in
(polarity, regex)
in
(polarity_regex issue_type_re, polarity_regex filename_re, reason_str)
| _ ->
L.(die UserError) "Ill-formed report filter: %s" str )
and filtering = !filtering
and flavors = !flavors

@ -415,6 +415,8 @@ val file_renamings : string option
val filter_paths : bool
val filter_report : ((bool * Str.regexp) * (bool * Str.regexp) * string) list
val filtering : bool
val flavors : bool

@ -36,7 +36,8 @@ let create_fake_jsonbug ?(bug_class= "bug_class") ?(kind= "kind") ?(bug_type= "b
; bug_type_hum= kind
; linters_def_file
; doc_url
; traceview_id= None }
; traceview_id= None
; censored_reason= "" }
let pp_diff_of_list ~pp group_name fmt (expected, actual) =

Loading…
Cancel
Save