[linters] Specify path in linters

Reviewed By: jvillard

Differential Revision: D5146904

fbshipit-source-id: 62b9d78
master
Dulma Churchill 8 years ago committed by Facebook Github Bot
parent 485814a75a
commit 46a539df82

@ -14,6 +14,7 @@ type keyword =
| Suggestion | Suggestion
| Severity | Severity
| Mode | Mode
| Path
type formula_id = Formula_id of string[@@deriving compare] type formula_id = Formula_id of string[@@deriving compare]
@ -46,6 +47,7 @@ let keyword_to_string k =
| Suggestion -> "suggestion" | Suggestion -> "suggestion"
| Severity -> "severity" | Severity -> "severity"
| Mode -> "mode" | Mode -> "mode"
| Path -> "path"
let is_report_when_keyword k = let is_report_when_keyword k =
match k with match k with
@ -72,6 +74,11 @@ let is_mode_keyword k =
| Mode -> true | Mode -> true
| _ -> false | _ -> false
let is_path_keyword k =
match k with
| Path -> true
| _ -> false
(* true if and only if a substring of container matches the regular (* true if and only if a substring of container matches the regular
expression defined by contained expression defined by contained
*) *)

@ -14,6 +14,7 @@ type keyword =
| Suggestion | Suggestion
| Severity | Severity
| Mode | Mode
| Path
type formula_id = Formula_id of string type formula_id = Formula_id of string
@ -43,6 +44,10 @@ val is_severity_keyword : keyword -> bool
val is_mode_keyword : keyword -> bool val is_mode_keyword : keyword -> bool
val is_path_keyword : keyword -> bool
val str_match_regex : string -> string -> bool
val compare_str_with_alexp : string -> alexp -> bool val compare_str_with_alexp : string -> alexp -> bool
module FormulaIdMap : Caml.Map.S with type key = formula_id module FormulaIdMap : Caml.Map.S with type key = formula_id

@ -256,7 +256,8 @@ let do_frontend_checks (trans_unit_ctx: CFrontend_config.translation_unit_contex
CTL.create_ctl_evaluation_tracker trans_unit_ctx.source_file; CTL.create_ctl_evaluation_tracker trans_unit_ctx.source_file;
try try
let parsed_linters = parse_ctl_files Config.linters_def_file in let parsed_linters = parse_ctl_files Config.linters_def_file in
let filtered_parsed_linters = CFrontend_errors.filter_parsed_linters parsed_linters in let filtered_parsed_linters =
CFrontend_errors.filter_parsed_linters parsed_linters trans_unit_ctx.source_file in
CFrontend_errors.parsed_linters := filtered_parsed_linters; CFrontend_errors.parsed_linters := filtered_parsed_linters;
let source_file = trans_unit_ctx.CFrontend_config.source_file in let source_file = trans_unit_ctx.CFrontend_config.source_file in
Logging.out "Start linting file %a with rules: @\n%s@\n" Logging.out "Start linting file %a with rules: @\n%s@\n"

@ -15,10 +15,11 @@ type linter = {
condition : CTL.t; condition : CTL.t;
issue_desc : CIssue.issue_desc; issue_desc : CIssue.issue_desc;
def_file : string option; def_file : string option;
path : string option;
} }
(* If in linter developer mode and if current linter was passed, filter it out *) (* If in linter developer mode and if current linter was passed, filter it out *)
let filter_parsed_linters parsed_linters = let filter_parsed_linters_developer parsed_linters =
if List.length parsed_linters > 1 && Config.linters_developer_mode then if List.length parsed_linters > 1 && Config.linters_developer_mode then
match Config.linter with match Config.linter with
| None -> | None ->
@ -31,6 +32,17 @@ let filter_parsed_linters parsed_linters =
) parsed_linters ) parsed_linters
else parsed_linters else parsed_linters
let filter_parsed_linters_by_path parsed_linters source_file =
let filter_parsed_linter_by_path linter =
match linter.path with
| Some path -> ALVar.str_match_regex (SourceFile.to_rel_path source_file) path
| None -> true in
List.filter ~f:filter_parsed_linter_by_path parsed_linters
let filter_parsed_linters parsed_linters source_file =
let linters = filter_parsed_linters_developer parsed_linters in
filter_parsed_linters_by_path linters source_file
let linters_to_string linters = let linters_to_string linters =
let linter_to_string linters = let linter_to_string linters =
List.map ~f:(fun (rule : linter) -> rule.issue_desc.name) linters in List.map ~f:(fun (rule : linter) -> rule.issue_desc.name) linters in
@ -126,39 +138,47 @@ let string_to_issue_mode m =
(Logging.out "\n[ERROR] Mode %s does not exist. Please specify ON/OFF\n" s; (Logging.out "\n[ERROR] Mode %s does not exist. Please specify ON/OFF\n" s;
assert false) assert false)
let string_to_path path = Some path
(** Convert a parsed checker in list of linters *) (** Convert a parsed checker in list of linters *)
let create_parsed_linters linters_def_file checkers : linter list = let create_parsed_linters linters_def_file checkers : linter list =
let open CIssue in let open CIssue in
let open CTL in let open CTL in
Logging.out "\n Converting checkers in (condition, issue) pairs\n"; Logging.out "\n Converting checkers in (condition, issue) pairs\n";
let do_one_checker c = let do_one_checker checker : linter =
let dummy_issue = { let dummy_issue = {
name = c.name; name = checker.name;
description = ""; description = "";
suggestion = None; suggestion = None;
loc = Location.dummy; loc = Location.dummy;
severity = Exceptions.Kwarning; severity = Exceptions.Kwarning;
mode = CIssue.On; mode = CIssue.On;
} in } in
let issue_desc, condition = List.fold ~f:(fun (issue', cond') d -> let issue_desc, condition, path =
match d with let process_linter_definitions (issue, cond, path) description =
match description with
| CSet (av, phi) when ALVar.is_report_when_keyword av -> | CSet (av, phi) when ALVar.is_report_when_keyword av ->
issue', phi issue, phi, path
| CDesc (av, msg) when ALVar.is_message_keyword av -> | CDesc (av, msg) when ALVar.is_message_keyword av ->
{issue' with description = msg}, cond' {issue with description = msg}, cond, path
| CDesc (av, sugg) when ALVar.is_suggestion_keyword av -> | CDesc (av, sugg) when ALVar.is_suggestion_keyword av ->
{issue' with suggestion = Some sugg}, cond' {issue with suggestion = Some sugg}, cond, path
| CDesc (av, sev) when ALVar.is_severity_keyword av -> | CDesc (av, sev) when ALVar.is_severity_keyword av ->
{issue' with severity = string_to_err_kind sev}, cond' {issue with severity = string_to_err_kind sev}, cond, path
| CDesc (av, m) when ALVar.is_mode_keyword av -> | CDesc (av, m) when ALVar.is_mode_keyword av ->
{issue' with mode = string_to_issue_mode m }, cond' {issue with mode = string_to_issue_mode m }, cond, path
| _ -> issue', cond') ~init:(dummy_issue, CTL.False) c.definitions in | CDesc (av, path') when ALVar.is_path_keyword av ->
if Config.debug_mode then ( issue, cond, string_to_path path'
| _ -> issue, cond, path in
List.fold
~f:process_linter_definitions
~init:(dummy_issue, CTL.False, None)
checker.definitions in
Logging.out "\nMaking condition and issue desc for checker '%s'\n" Logging.out "\nMaking condition and issue desc for checker '%s'\n"
c.name; checker.name;
Logging.out "\nCondition =\n %a\n" CTL.Debug.pp_formula condition; Logging.out "\nCondition =\n %a\n" CTL.Debug.pp_formula condition;
Logging.out "\nIssue_desc = %a\n" CIssue.pp_issue issue_desc); Logging.out "\nIssue_desc = %a\n" CIssue.pp_issue issue_desc;
{condition; issue_desc; def_file = Some linters_def_file} in {condition; issue_desc; def_file = Some linters_def_file; path;} in
List.map ~f:do_one_checker checkers List.map ~f:do_one_checker checkers
let rec apply_substitution f sub = let rec apply_substitution f sub =

@ -13,9 +13,10 @@ type linter = {
condition : CTL.t; condition : CTL.t;
issue_desc : CIssue.issue_desc; issue_desc : CIssue.issue_desc;
def_file : string option; def_file : string option;
path : string option;
} }
val filter_parsed_linters : linter list -> linter list val filter_parsed_linters : linter list -> SourceFile.t -> linter list
val linters_to_string : linter list -> string val linters_to_string : linter list -> string

@ -148,8 +148,10 @@ clause:
| "suggestion" -> ALVar.Suggestion | "suggestion" -> ALVar.Suggestion
| "severity" -> ALVar.Severity | "severity" -> ALVar.Severity
| "mode" -> ALVar.Mode | "mode" -> ALVar.Mode
| _ -> failwith ("[ERROR] string '%s' cannot be set in a SET clause. " ^ | "path" -> ALVar.Path
"Use either of: 'message', 'suggestion', 'severity', or 'mode'\n") in | _ -> IStd.failwithf "[ERROR] string '%s' cannot be set in a SET clause. \
Use either of: \
'message', 'mode', 'severity', 'suggestion' or 'path'" $2 in
CTL.CDesc (alvar, $4) } CTL.CDesc (alvar, $4) }
| let_clause { $1 } | let_clause { $1 }
; ;

@ -38,11 +38,6 @@ let ast_node_name an =
| _ -> "" | _ -> ""
let infer_prefix = "__infer_ctl_" let infer_prefix = "__infer_ctl_"
let report_when_const = "report_when"
let message_const = "message"
let suggestion_const = "suggestion"
let severity_const = "severity"
let mode_const = "mode"
exception ALParsingException of string exception ALParsingException of string

@ -21,11 +21,6 @@ val ast_node_type : ast_node -> string
exception ALParsingException of string exception ALParsingException of string
val infer_prefix : string val infer_prefix : string
val report_when_const : string
val message_const : string
val suggestion_const : string
val severity_const : string
val mode_const : string
(** Data structures for type parser. (** Data structures for type parser.
Correspondence with clang types inferred from Correspondence with clang types inferred from

@ -0,0 +1,9 @@
/*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
int main() { return 0; }

@ -1,3 +1,8 @@
codetoanalyze/objc/linters-for-test-only/filter_by_path/include_file.m, main, 9, ALL_PATH_NO_FILTER_EXAMPLE, []
codetoanalyze/objc/linters-for-test-only/filter_by_path/include_file.m, main, 9, FILTER_BY_ALL_PATH_EXAMPLE, []
codetoanalyze/objc/linters-for-test-only/filter_by_path/include_file.m, main, 9, FILTER_BY_PATH_EXAMPLE, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 9, ALL_PATH_NO_FILTER_EXAMPLE, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 9, FILTER_BY_ALL_PATH_EXAMPLE, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 10, TEST_VAR_TYPE_CHECK, [] codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 10, TEST_VAR_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 11, TEST_IMPLICIT_CAST_CHECK, [] codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 11, TEST_IMPLICIT_CAST_CHECK, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 11, TEST_VAR_TYPE_CHECK, [] codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 11, TEST_VAR_TYPE_CHECK, []

@ -215,3 +215,26 @@ DEFINE-CHECKER TEST_NAMESPACE_NAME = {
SET message = "Found a namespace with name...."; SET message = "Found a namespace with name....";
}; };
DEFINE-CHECKER FILTER_BY_PATH_EXAMPLE = {
SET report_when =
WHEN declaration_has_name("main")
HOLDS-IN-NODE FunctionDecl;
SET message = "Found main method";
SET path = "codetoanalyze/objc/linters-for-test-only/filter_by_path/.*";
};
DEFINE-CHECKER ALL_PATH_NO_FILTER_EXAMPLE = {
SET report_when =
WHEN declaration_has_name("main")
HOLDS-IN-NODE FunctionDecl;
SET message = "Found main method";
};
DEFINE-CHECKER FILTER_BY_ALL_PATH_EXAMPLE = {
SET report_when =
WHEN declaration_has_name("main")
HOLDS-IN-NODE FunctionDecl;
SET message = "Found main method";
SET path = ".*";
};

Loading…
Cancel
Save