From 6ffaded4be734b6f8ddf2013f22f8d8562d17434 Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Fri, 11 Nov 2016 07:59:59 -0800 Subject: [PATCH] Modified the hardcoded CTL formulas in preparation to dispatcher removal Reviewed By: dulmarod Differential Revision: D4130612 fbshipit-source-id: d482966 --- infer/src/clang/CLintersContext.ml | 2 + infer/src/clang/cFrontend_checkers.ml | 49 +++++----- infer/src/clang/cFrontend_errors.ml | 42 +-------- infer/src/clang/cTL.ml | 91 +++++++++++++++---- infer/src/clang/cTL.mli | 4 + infer/src/clang/predicates.ml | 14 +-- infer/src/clang/predicates.mli | 4 +- .../codetoanalyze/objc/linters/badpointer.m | 17 ++++ .../codetoanalyze/objc/linters/issues.exp | 2 + 9 files changed, 136 insertions(+), 89 deletions(-) diff --git a/infer/src/clang/CLintersContext.ml b/infer/src/clang/CLintersContext.ml index 84367c269..fd7cad7df 100644 --- a/infer/src/clang/CLintersContext.ml +++ b/infer/src/clang/CLintersContext.ml @@ -18,6 +18,7 @@ type context = { current_objc_impl : Clang_ast_t.decl option; (** True if inside an objc static factory method (a class-level initializer, like +new) *) in_objc_static_factory_method : bool; + et_evaluation_node : string option; } let empty translation_unit_context = { @@ -27,4 +28,5 @@ let empty translation_unit_context = { is_ck_translation_unit = false; current_objc_impl = None; in_objc_static_factory_method = false; + et_evaluation_node = None; } diff --git a/infer/src/clang/cFrontend_checkers.ml b/infer/src/clang/cFrontend_checkers.ml index 2f681725a..d41fd9496 100644 --- a/infer/src/clang/cFrontend_checkers.ml +++ b/infer/src/clang/cFrontend_checkers.ml @@ -59,13 +59,12 @@ let ivar_name stmt = || is_CXXOperatorCallExpr || is_ObjCMessageExpr *) let ctl_makes_an_expensive_call () = let open CTL in - let white_list_functions = ["CGPointMake"] in - Or (Or (Or (Or (And (Atomic ("is_statement_kind", ["CallExpr"]), - Not(Atomic("call_function_named", white_list_functions))), - Atomic ("is_statement_kind", ["CXXTemporaryObjectExpr"])), - Atomic ("is_statement_kind", ["CXXMemberCallExpr"])), - Atomic ("is_statement_kind", ["CXXOperatorCallExpr"])), - Atomic ("is_statement_kind", ["ObjCMessageExpr"])) + Or (Or (Or (Or (And (Atomic ("is_stmt", ["CallExpr"]), + Not (Atomic("call_function_named", ["CGPointMake"]))), + Atomic ("is_stmt", ["CXXTemporaryObjectExpr"])), + Atomic ("is_stmt", ["CXXMemberCallExpr"])), + Atomic ("is_stmt", ["CXXOperatorCallExpr"])), + Atomic ("is_stmt", ["ObjCMessageExpr"])) (* @@ -128,7 +127,8 @@ let ctl_bad_pointer_comparison_warning lctx stmt = *) let p = Or (is_expr_with_cleanups, Or (is_implicit_cast_expr, Or (is_binop, is_unop_lnot))) in let p' = And (Not is_binop_neq, p) in - let condition = EU (None, p', is_nsnumber) in + let condition = ETX (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], Some Cond, + EU (None, p', is_nsnumber)) in let issue_desc = { CIssue. issue = CIssue.Bad_pointer_comparison; @@ -150,9 +150,9 @@ let ctl_strong_delegate lctx dec = Not(Atomic ("property_name_contains_word", ["queue"])) in let is_strong_property = Atomic("is_strong_property", []) in - let condition = And (name_contains_delegate, - And (name_does_not_contains_queue, - is_strong_property)) in + let condition = ET (["ObjCPropertyDecl"], None, And (name_contains_delegate, + And (name_does_not_contains_queue, + is_strong_property))) in let issue_desc = { CIssue.issue = CIssue.Strong_delegate_warning; CIssue.description = Printf.sprintf @@ -172,7 +172,8 @@ let ctl_global_var_init_with_calls_warning lctx decl = Not (Atomic ("is_const_var", []))) in let ctl_is_initialized_with_expensive_call = ET(["VarDecl"], Some InitExpr, EF (None, (ctl_makes_an_expensive_call ()))) in - let condition = And (ctl_is_global_var, ctl_is_initialized_with_expensive_call) in + let condition = + ET (["VarDecl"], None, And (ctl_is_global_var, ctl_is_initialized_with_expensive_call)) in let issue_desc = { CIssue.issue = CIssue.Global_variable_initialized_with_function_or_method_call; CIssue.description = Printf.sprintf @@ -187,8 +188,9 @@ let ctl_global_var_init_with_calls_warning lctx decl = (* is_assign_property AND is_property_pointer_type *) let ctl_assign_pointer_warning lctx decl = let open CTL in - let condition = - And (Atomic("is_assign_property", []), Atomic("is_property_pointer_type", [])) in + let condition = ET(["ObjCPropertyDecl"], None, + And (Atomic ("is_assign_property", []), + Atomic ("is_property_pointer_type", []))) in let issue_desc = { CIssue.issue = CIssue.Assign_pointer_warning; CIssue.description = @@ -206,12 +208,12 @@ let ctl_assign_pointer_warning lctx decl = *) let ctl_direct_atomic_property_access_warning lctx stmt = let open CTL in - let condition = - And (And (And (And (Not (Atomic ("context_in_synchronized_block", [])), - Atomic("is_ivar_atomic", [])), - Not (Atomic ("is_method_property_accessor_of_ivar", []))), - Not (Atomic ("is_objc_constructor", []))), - Not (Atomic ("is_objc_dealloc", []))) in + let condition = ET (["ObjCIvarRefExpr"], None, + And (And (And (And (Not (Atomic ("context_in_synchronized_block", [])), + Atomic("is_ivar_atomic", [])), + Not (Atomic ("is_method_property_accessor_of_ivar", []))), + Not (Atomic ("is_objc_constructor", []))), + Not (Atomic ("is_objc_dealloc", [])))) in let issue_desc = { CIssue.issue = CIssue.Direct_atomic_property_access; CIssue.description = Printf.sprintf @@ -224,7 +226,8 @@ let ctl_direct_atomic_property_access_warning lctx stmt = let ctl_captured_cxx_ref_in_objc_block_warning lctx stmt = (* Fire if the list of captured references is not empty *) - let condition = CTL.Atomic ("captures_cxx_references", []) in + let open CTL in + let condition = ET (["BlockDecl"], None, Atomic ("captures_cxx_references", [])) in let issue_desc = { CIssue.issue = CIssue.Cxx_reference_captured_in_objc_block; CIssue.description = Printf.sprintf @@ -232,7 +235,9 @@ let ctl_captured_cxx_ref_in_objc_block_warning lctx stmt = (Predicates.var_descs_name stmt); CIssue.suggestion = Some ("C++ References are unmanaged and may be invalid " ^ "by the time the block executes."); - CIssue.loc = location_from_stmt lctx stmt + CIssue.loc = match stmt with + | Clang_ast_t.BlockExpr (_, _ , _, decl) -> location_from_decl lctx decl + | _ -> location_from_stmt lctx stmt; } in condition, issue_desc diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index 6a4dcf2fd..0a2276a6e 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -63,13 +63,6 @@ let var_checker_list = [CFrontend_checkers.global_var_init_with_calls_warning; let checker_for_var dec checker context = checker context dec -(* List of checkers on conditional operator *) -let conditional_op_checker_list = [CFrontend_checkers.bad_pointer_comparison_warning] - -(* Invocation of checker belonging to conditional_op_checker_list *) -let checker_for_conditional_op first_stmt checker context = - checker context first_stmt - (* List of checkers on if-statement *) let if_stmt_checker_list = [CFrontend_checkers.bad_pointer_comparison_warning] @@ -77,20 +70,6 @@ let if_stmt_checker_list = [CFrontend_checkers.bad_pointer_comparison_warning] let checker_for_if_stmt cond checker context = checker context cond -(* List of checkers on for statement *) -let for_stmt_checker_list = [CFrontend_checkers.bad_pointer_comparison_warning] - -(* Invocation of checker belonging to for_stmt_checker_list *) -let checker_for_for_stmt cond checker context = - checker context cond - -(* List of checkers on while statement *) -let while_stmt_checker_list = [CFrontend_checkers.bad_pointer_comparison_warning] - -(* Invocation of checker belonging to while_stmt_checker_list *) -let checker_for_while_stmt cond checker context = - checker context cond - let function_decl_checker_list = [ComponentKit.component_factory_function_advice] let checker_for_function_decl decl checker context = @@ -146,26 +125,11 @@ let run_frontend_checkers_on_stmt context instr = invoke_set_of_checkers call_captured_vars_checker context key captured_vars_checker_list; context - | IfStmt (_, _ :: _ :: cond :: _) -> - let call_checker = checker_for_if_stmt cond in - let key = Ast_utils.generate_key_stmt cond in + | IfStmt _ | ConditionalOperator _ | ForStmt _ | WhileStmt _ -> + let call_checker = checker_for_if_stmt instr in + let key = Ast_utils.generate_key_stmt instr in invoke_set_of_checkers call_checker context key if_stmt_checker_list; context - | ConditionalOperator (_, first_stmt :: _, _) -> - let call_checker = checker_for_conditional_op first_stmt in - let key = Ast_utils.generate_key_stmt first_stmt in - invoke_set_of_checkers call_checker context key conditional_op_checker_list; - context - | ForStmt (_, [_; _; cond; _; _]) -> - let call_checker = checker_for_for_stmt cond in - let key = Ast_utils.generate_key_stmt cond in - invoke_set_of_checkers call_checker context key for_stmt_checker_list; - context - | WhileStmt (_, [_; cond; _]) -> - let call_checker = checker_for_while_stmt cond in - let key = Ast_utils.generate_key_stmt cond in - invoke_set_of_checkers call_checker context key while_stmt_checker_list; - context | CallExpr (_, called_func_stmt :: _, _) -> let call_checker = checkers_for_call_expr called_func_stmt in let key = Ast_utils.generate_key_stmt called_func_stmt in diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index 41f7565db..28a388c29 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -22,6 +22,7 @@ type transitions = | Body (* decl to stmt *) | InitExpr (* decl to stmt *) | Super (* decl to decl *) + | Cond (* In formulas below prefix "E" means "exists a path" @@ -46,6 +47,7 @@ type t = (* A ctl formula *) | EU of transitions option * t * t | EH of string list * t | ET of string list * transitions option * t + | ETX of string list * transitions option * t (* the kind of AST nodes where formulas are evaluated *) type ast_node = @@ -57,19 +59,28 @@ module Debug = struct let pp_aux fmt trans = match trans with | Body -> Format.pp_print_string fmt "Body" | InitExpr -> Format.pp_print_string fmt "InitExpr" - | Super -> Format.pp_print_string fmt "Super" in + | Super -> Format.pp_print_string fmt "Super" + | Cond -> Format.pp_print_string fmt "Cond" in match trans_opt with | Some trans -> pp_aux fmt trans | None -> Format.pp_print_string fmt "_" + (* a flag to print more or less in the dotty graph *) + let full_print = true + let rec pp_formula fmt phi = match phi with | True -> Format.fprintf fmt "True" | False -> Format.fprintf fmt "False" | Atomic p -> Predicates.pp_predicate fmt p - | Not phi -> Format.fprintf fmt "NOT(%a)" pp_formula phi - | And (phi1, phi2) -> Format.fprintf fmt "(%a AND %a)" pp_formula phi1 pp_formula phi2 - | Or (phi1, phi2) -> Format.fprintf fmt "(%a OR %a)" pp_formula phi1 pp_formula phi2 + | Not phi -> if full_print then Format.fprintf fmt "NOT(%a)" pp_formula phi + else Format.fprintf fmt "NOT(...)" + | And (phi1, phi2) -> if full_print then + Format.fprintf fmt "(%a AND %a)" pp_formula phi1 pp_formula phi2 + else Format.fprintf fmt "(... AND ...)" + | Or (phi1, phi2) -> if full_print then + Format.fprintf fmt "(%a OR %a)" pp_formula phi1 pp_formula phi2 + else Format.fprintf fmt "(... OR ...)" | Implies (phi1, phi2) -> Format.fprintf fmt "(%a ==> %a)" pp_formula phi1 pp_formula phi2 | InNode (nl, phi) -> Format.fprintf fmt "IN-NODE %a: (%a)" (Utils.pp_comma_seq Format.pp_print_string) nl @@ -86,10 +97,11 @@ module Debug = struct | EH (arglist, phi) -> Format.fprintf fmt "EH[%a](%a)" (Utils.pp_comma_seq Format.pp_print_string) arglist pp_formula phi - | ET (arglist, trans, phi) -> Format.fprintf fmt "ET[%a][%a](%a)" - (Utils.pp_comma_seq Format.pp_print_string) arglist - pp_transition trans - pp_formula phi + | ET (arglist, trans, phi) + | ETX (arglist, trans, phi) -> Format.fprintf fmt "ET[%a][%a](%a)" + (Utils.pp_comma_seq Format.pp_print_string) arglist + pp_transition trans + pp_formula phi module EvaluationTracker = struct exception Empty_stack of string @@ -99,6 +111,7 @@ module Debug = struct type content = { ast_node: ast_node; phi: t; + lcxt: CLintersContext.context; eval_result: eval_result; } @@ -115,9 +128,9 @@ module Debug = struct forest: tree list; } - let create_content ast_node phi = {ast_node; phi; eval_result = Eval_undefined} + let create_content ast_node phi lcxt = {ast_node; phi; eval_result = Eval_undefined; lcxt = lcxt; } - let create () = {next_id = 0; eval_stack = Stack.create(); forest = []} + let create () = {next_id = 0; eval_stack = Stack.create(); forest = [] } let eval_begin t content = let node = {id = t.next_id; content} in @@ -169,6 +182,10 @@ module Debug = struct | Eval_false -> "red" | _ -> failwith "Tree is not fully evaluated" in let label = + let string_of_lcxt c = + match c.CLintersContext.et_evaluation_node with + | Some s -> ("et_evaluation_node = "^s) + | _ -> "et_evaluation_node = NONE" in let string_of_ast_node an = match an with | Stmt stmt -> Clang_ast_proj.get_stmt_kind_string stmt @@ -181,9 +198,10 @@ module Debug = struct | Implies _ when num_children = 2 -> "(...) ==> (...)" | Not _ -> "NOT(...)" | _ -> Utils.pp_to_string pp_formula phi in - Format.sprintf "(%d)\\n%s\\n%s" + Format.sprintf "(%d)\\n%s\\n%s\\n%s" root_node.id (Escape.escape_dotty (string_of_ast_node root_node.content.ast_node)) + (Escape.escape_dotty (string_of_lcxt root_node.content.lcxt)) (Escape.escape_dotty (smart_string_of_formula root_node.content.phi)) in let edges = let buf = Buffer.create 16 in @@ -212,9 +230,9 @@ let ctl_evaluation_tracker = match Config.debug_mode with | true -> Some (ref (Debug.EvaluationTracker.create ())) | false -> None -let debug_create_payload ast_node phi = +let debug_create_payload ast_node phi lcxt = match ctl_evaluation_tracker with - | Some _ -> Some (Debug.EvaluationTracker.create_content ast_node phi) + | Some _ -> Some (Debug.EvaluationTracker.create_content ast_node phi lcxt) | None -> None let debug_eval_begin payload = @@ -258,6 +276,15 @@ let node_to_string an = | Decl d -> Clang_ast_proj.get_decl_kind_string d | Stmt s -> Clang_ast_proj.get_stmt_kind_string s +let node_to_unique_string_id an = + match an with + | Decl d -> + let di = Clang_ast_proj.get_decl_tuple d in + (Clang_ast_proj.get_decl_kind_string d) ^ (string_of_int di.Clang_ast_t.di_pointer) + | Stmt s -> + let si, _ = Clang_ast_proj.get_stmt_tuple s in + Clang_ast_proj.get_stmt_kind_string s ^ (string_of_int si.Clang_ast_t.si_pointer) + (* true iff an ast node is a node of type among the list tl *) let node_has_type tl an = let an_str = node_to_string an in @@ -298,12 +325,22 @@ let transition_decl_to_decl_via_super d = | _ -> None) | None -> None +let transition_stmt_to_stmt_via_condition st = + let open Clang_ast_t in + match st with + | IfStmt (_, _ :: _ :: cond :: _) + | ConditionalOperator (_, cond:: _, _) + | ForStmt (_, [_; _; cond; _; _]) + | WhileStmt (_, [_; cond; _]) -> Some (Stmt cond) + | _ -> None + (* given a node an returns the node an' such that an transition to an' via label trans *) let next_state_via_transition an trans = match an, trans with | Decl d, Some Super -> transition_decl_to_decl_via_super d | Decl d, Some InitExpr | Decl d, Some Body -> transition_decl_to_stmt d trans + | Stmt st, Some Cond -> transition_stmt_to_stmt_via_condition st | _, _ -> None (* Evaluation of formulas *) @@ -318,7 +355,6 @@ let eval_Atomic pred_name params an lcxt = | "is_global_var", [], Decl d -> Predicates.is_syntactically_global_var d | "is_const_var", [], Decl d -> Predicates.is_const_expr_var d | "call_function_named", _, Stmt st -> Predicates.call_function_named st params - | "is_statement_kind", [p1], Stmt st -> Predicates.is_statement_kind st p1 | "is_declaration_kind", [p1], Decl d -> Predicates.is_declaration_kind d p1 | "is_strong_property", [], Decl d -> Predicates.is_strong_property d | "is_assign_property", [], Decl d -> Predicates.is_assign_property d @@ -329,7 +365,7 @@ let eval_Atomic pred_name params an lcxt = Predicates.is_method_property_accessor_of_ivar st lcxt | "is_objc_constructor", [], _ -> Predicates.is_objc_constructor lcxt | "is_objc_dealloc", [], _ -> Predicates.is_objc_dealloc lcxt - | "captures_cxx_references", [], Stmt st -> Predicates.captures_cxx_references st + | "captures_cxx_references", [], Decl d -> Predicates.captures_cxx_references d | "is_binop_with_kind", [kind], Stmt st -> Predicates.is_binop_with_kind st kind | "is_unop_with_kind", [kind], Stmt st -> Predicates.is_unop_with_kind st kind | "is_stmt", [stmt_name], Stmt st -> Predicates.is_stmt st stmt_name @@ -428,7 +464,14 @@ and eval_AU phi1 phi2 an lcxt = an is a node of type in node_type_list and an satifies phi *) and in_node node_type_list phi an lctx = - (node_has_type node_type_list an) && (eval_formula phi an lctx) + let holds_for_one_node n = + match lctx.CLintersContext.et_evaluation_node with + | Some id -> + (string_equal id (node_to_unique_string_id an)) && (eval_formula phi an lctx) + | None -> + (node_has_type [n] an) && (eval_formula phi an lctx) in + IList.exists holds_for_one_node node_type_list + (* Intuitive meaning: (an,lcxt) satifies EH[Classes] phi if the node an is among the declaration specified by the list Classes and @@ -458,9 +501,20 @@ and eval_ET tl trs phi an lcxt = | None -> EF (None, (InNode (tl, phi))) in eval_formula f an lcxt +and eval_ETX tl trs phi an lcxt = + let lcxt', tl' = match lcxt.CLintersContext.et_evaluation_node, node_has_type tl an with + | None, true -> + let an_str = node_to_string an in + {lcxt with CLintersContext.et_evaluation_node = Some (node_to_unique_string_id an) }, [an_str] + | _, _ -> lcxt, tl in + let f = match trs with + | Some _ -> EF (None, (InNode (tl', EX (trs, phi)))) + | None -> EF (None, (InNode (tl', phi))) in + eval_formula f an lcxt' + (* Formulas are evaluated on a AST node an and a linter context lcxt *) and eval_formula f an lcxt = - debug_eval_begin (debug_create_payload an f); + debug_eval_begin (debug_create_payload an f lcxt); let res = match f with | True -> true | False -> false @@ -483,6 +537,7 @@ and eval_formula f an lcxt = | EH (cl, phi) -> eval_EH cl phi an lcxt | EG (trans, f1) -> (* st |= EG f1 <=> st |= f1 /\ EX EG f1 *) eval_formula (And (f1, EX (trans, (EG (trans, f1))))) an lcxt - | ET (tl, sw, phi) -> eval_ET tl sw phi an lcxt in + | ET (tl, sw, phi) -> eval_ET tl sw phi an lcxt + | ETX (tl, sw, phi) -> eval_ETX tl sw phi an lcxt in debug_eval_end res; res diff --git a/infer/src/clang/cTL.mli b/infer/src/clang/cTL.mli index bea148926..7fb62d1a3 100644 --- a/infer/src/clang/cTL.mli +++ b/infer/src/clang/cTL.mli @@ -17,6 +17,7 @@ type transitions = | Body (* decl to stmt *) | InitExpr (* decl to stmt *) | Super (* decl to decl *) + | Cond (* In formulas below prefix "E" means "exists a path" @@ -49,6 +50,9 @@ type t = | ET of string list * transitions option * t (** ET[T][l] phi <=> there exists a descentant an of the current node such that an is of type in set T making a transition to a node an' via label l, such that in an phi holds. *) + | ETX of string list * transitions option * t (** ET[T][l] phi <=> + there exists a descentant an of the current node such that an is of type in set T + making a transition to a node an' via label l, such that in an phi holds. *) (** the kind of AST nodes where formulas are evaluated *) type ast_node = diff --git a/infer/src/clang/predicates.ml b/infer/src/clang/predicates.ml index 977c212e6..f3c0a4e82 100644 --- a/infer/src/clang/predicates.ml +++ b/infer/src/clang/predicates.ml @@ -23,7 +23,7 @@ let get_ivar_attributes ivar_decl = | _ -> [] (* list of cxx references captured by stmt *) -let captured_variables_cxx_ref stmt = +let captured_variables_cxx_ref dec = let capture_var_is_cxx_ref reference_captured_vars captured_var = let decl_ref_opt = captured_var.Clang_ast_t.bcv_variable in match Ast_utils.get_decl_opt_with_decl_ref decl_ref_opt with @@ -35,14 +35,17 @@ let captured_variables_cxx_ref stmt = named_decl_info::reference_captured_vars | _ -> reference_captured_vars) | _ -> reference_captured_vars in - let captured_vars = match stmt with - | Clang_ast_t.BlockExpr (_, _ , _, Clang_ast_t.BlockDecl (_, bdi)) -> + let captured_vars = match dec with + | Clang_ast_t.BlockDecl (_, bdi) -> bdi.Clang_ast_t.bdi_captured_variables | _ -> [] in IList.fold_left capture_var_is_cxx_ref [] captured_vars let var_descs_name stmt = - let capt_refs = captured_variables_cxx_ref stmt in + let capt_refs = match stmt with + | Clang_ast_t.BlockExpr (_, _ , _, decl) -> + captured_variables_cxx_ref decl + | _ -> [] in let var_desc vars var_named_decl_info = vars ^ "'" ^ var_named_decl_info.Clang_ast_t.ni_name ^ "'" in IList.fold_left var_desc "" capt_refs @@ -56,9 +59,6 @@ let pp_predicate fmt (name, arglist) = let is_declaration_kind decl s = Clang_ast_proj.get_decl_kind_string decl = s -let is_statement_kind stmt s = - Clang_ast_proj.get_stmt_kind_string stmt = s - (* st |= call_method(m) *) let call_method m st = match st with diff --git a/infer/src/clang/predicates.mli b/infer/src/clang/predicates.mli index b855d0f0d..cf4596bdf 100644 --- a/infer/src/clang/predicates.mli +++ b/infer/src/clang/predicates.mli @@ -23,8 +23,6 @@ val is_const_expr_var : Clang_ast_t.decl -> bool val is_declaration_kind : Clang_ast_t.decl -> string -> bool -val is_statement_kind : Clang_ast_t.stmt -> string -> bool - val call_function_named : Clang_ast_t.stmt -> string list -> bool val is_strong_property : Clang_ast_t.decl -> bool @@ -43,7 +41,7 @@ val is_objc_constructor : CLintersContext.context -> bool val is_objc_dealloc : CLintersContext.context -> bool -val captures_cxx_references : Clang_ast_t.stmt -> bool +val captures_cxx_references : Clang_ast_t.decl -> bool val is_binop_with_kind : Clang_ast_t.stmt -> string -> bool diff --git a/infer/tests/codetoanalyze/objc/linters/badpointer.m b/infer/tests/codetoanalyze/objc/linters/badpointer.m index 868bc01dc..127cede96 100644 --- a/infer/tests/codetoanalyze/objc/linters/badpointer.m +++ b/infer/tests/codetoanalyze/objc/linters/badpointer.m @@ -142,4 +142,21 @@ int bad10(NSNumber* number, Simple* simple) { return 0; } +int bad11(int i, NSNumber* number) { + if (i > 10) { + return 11; + } else if (number) { + return 0; + } + return 1; +} + int good6(NSNumber* number) { return (number.integerValue > 5 ? 1 : 0); } + +NSNumber* good7(NSNumber* number) { + return (number.integerValue > 5 ? number : @0); +} + +NSNumber* bad12(NSNumber* number) { + return (number.integerValue > 5 ? (number ? @1 : @0) : @0); +} diff --git a/infer/tests/codetoanalyze/objc/linters/issues.exp b/infer/tests/codetoanalyze/objc/linters/issues.exp index 1327e76a6..6f8b03f4d 100644 --- a/infer/tests/codetoanalyze/objc/linters/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters/issues.exp @@ -10,6 +10,8 @@ atomic_prop.m, A_writeQ:, 82, DIRECT_ATOMIC_PROPERTY_ACCESS atomic_prop.m, __objc_anonymous_block_______1, 114, DIRECT_ATOMIC_PROPERTY_ACCESS badpointer.m, bad1, 17, BAD_POINTER_COMPARISON badpointer.m, bad10, 139, BAD_POINTER_COMPARISON +badpointer.m, bad11, 148, BAD_POINTER_COMPARISON +badpointer.m, bad12, 161, BAD_POINTER_COMPARISON badpointer.m, bad2, 26, BAD_POINTER_COMPARISON badpointer.m, bad3, 33, BAD_POINTER_COMPARISON badpointer.m, bad4, 85, BAD_POINTER_COMPARISON