From 0ed033a32e5b4df83e677e6be9a51fb946741039 Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Thu, 17 Nov 2016 04:01:10 -0800 Subject: [PATCH] Removing the dispatcher for linters. Reviewed By: dulmarod Differential Revision: D4182551 fbshipit-source-id: af7c88e --- infer/src/clang/ComponentKit.ml | 74 +++++---- infer/src/clang/ComponentKit.mli | 10 +- infer/src/clang/cFrontend_checkers.ml | 179 +++++++++------------ infer/src/clang/cFrontend_checkers.mli | 28 ++-- infer/src/clang/cFrontend_checkers_main.ml | 4 +- infer/src/clang/cFrontend_errors.ml | 153 ++++-------------- infer/src/clang/cFrontend_errors.mli | 10 +- infer/src/clang/predicates.ml | 8 - infer/src/clang/predicates.mli | 2 +- 9 files changed, 168 insertions(+), 300 deletions(-) diff --git a/infer/src/clang/ComponentKit.ml b/infer/src/clang/ComponentKit.ml index 07076ee29..eeddfccfe 100644 --- a/infer/src/clang/ComponentKit.ml +++ b/infer/src/clang/ComponentKit.ml @@ -64,7 +64,7 @@ and contains_ck_impl decl_list = const int *z; const NSString *y; ``` *) -let mutable_local_vars_advice context decl = +let mutable_local_vars_advice context an = let rec get_referenced_type (qual_type: Clang_ast_t.qual_type) : Clang_ast_t.decl option = let typ_opt = Ast_utils.get_desugared_type qual_type.qt_type_ptr in match (typ_opt : Clang_ast_t.c_type option) with @@ -85,8 +85,8 @@ let mutable_local_vars_advice context decl = IList.mem string_equal ndi.ni_name objc_whitelist | _ -> false in - match decl with - | Clang_ast_t.VarDecl(decl_info, named_decl_info, qual_type, _) -> + match an with + | CTL.Decl (Clang_ast_t.VarDecl(decl_info, named_decl_info, qual_type, _) as decl)-> let is_const_ref = match Ast_utils.get_type qual_type.qt_type_ptr with | Some LValueReferenceType (_, {Clang_ast_t.qt_is_const}) -> qt_is_const @@ -98,33 +98,33 @@ let mutable_local_vars_advice context decl = && not (is_of_whitelisted_type qual_type) && not decl_info.di_is_implicit in if condition then - Some { + CTL.True, Some { CIssue.issue = CIssue.Mutable_local_variable_in_component_file; CIssue.description = "Local variable '" ^ named_decl_info.ni_name ^ "' should be const to avoid reassignment"; CIssue.suggestion = Some "Add a const (after the asterisk for pointer types)."; CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info } - else None - | _ -> assert false (* Should only be called with a VarDecl *) + else CTL.False, None + | _ -> CTL.False, None (* Should only be called with a VarDecl *) (** Catches functions that should be composite components. http://componentkit.org/docs/break-out-composites.html Any static function that returns a subclass of CKComponent will be flagged. *) -let component_factory_function_advice context decl = +let component_factory_function_advice context an = let is_component_if decl = Ast_utils.is_objc_if_descendant decl [CFrontend_config.ckcomponent_cl] in - match decl with - | Clang_ast_t.FunctionDecl (decl_info, _, (qual_type: Clang_ast_t.qual_type), _) -> + match an with + | CTL.Decl (Clang_ast_t.FunctionDecl (decl_info, _, (qual_type: Clang_ast_t.qual_type), _) as decl) -> let objc_interface = Ast_utils.type_ptr_to_objc_interface qual_type.qt_type_ptr in let condition = is_ck_context context decl && is_component_if objc_interface in if condition then - Some { + CTL.True, Some { CIssue.issue = CIssue.Component_factory_function; CIssue.description = "Break out composite components"; CIssue.suggestion = Some ( @@ -133,13 +133,13 @@ let component_factory_function_advice context decl = ); CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info } - else None - | _ -> assert false (* Should only be called with FunctionDecl *) + else CTL.False, None + | _ -> CTL.False, None (* Should only be called with FunctionDecl *) (** Components should not inherit from each other. They should instead inherit from CKComponent, CKCompositeComponent, or CKStatefulViewComponent. (Similar rule applies to component controllers.) *) -let component_with_unconventional_superclass_advice context decl = +let component_with_unconventional_superclass_advice context an = let check_interface if_decl = match if_decl with | Clang_ast_t.ObjCInterfaceDecl (_, _, _, _, _) -> @@ -164,7 +164,7 @@ let component_with_unconventional_superclass_advice context decl = is_component_or_controller_if (Some if_decl) && not has_conventional_superclass in if condition then - Some { + CTL.True, Some { CIssue.issue = CIssue.Component_with_unconventional_superclass; CIssue.description = "Never Subclass Components"; CIssue.suggestion = Some ( @@ -173,19 +173,19 @@ let component_with_unconventional_superclass_advice context decl = CIssue.loc = CFrontend_checkers.location_from_decl context if_decl } else - None + CTL.False, None else - None + CTL.False, None | _ -> assert false in - match decl with - | Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) -> + match an with + | CTL.Decl (Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) as decl) -> let if_decl_opt = Ast_utils.get_decl_opt_with_decl_ref impl_decl_info.oidi_class_interface in if Option.is_some if_decl_opt && is_ck_context context decl then check_interface (Option.get if_decl_opt) else - None - | _ -> assert false + CTL.False, None + | _ -> CTL.False, None (** Components should only have one factory method. @@ -197,7 +197,7 @@ let component_with_unconventional_superclass_advice context decl = it. While its existence is probably not good, I can't think of any reason there would be factory methods that aren't exposed outside of a class is not useful if there's only one public factory method. *) -let component_with_multiple_factory_methods_advice context decl = +let component_with_multiple_factory_methods_advice context an = let is_unavailable_attr attr = match attr with | Clang_ast_t.UnavailableAttr _ -> true | _ -> false in @@ -214,7 +214,7 @@ let component_with_multiple_factory_methods_advice context decl = | Clang_ast_t.ObjCInterfaceDecl (decl_info, _, decls, _, _) -> let factory_methods = IList.filter (is_available_factory_method if_decl) decls in if (IList.length factory_methods) > 1 then - Some { + CTL.True, Some { CIssue.issue = CIssue.Component_with_multiple_factory_methods; CIssue.description = "Avoid Overrides"; CIssue.suggestion = @@ -223,16 +223,16 @@ let component_with_multiple_factory_methods_advice context decl = CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info } else - None + CTL.False, None | _ -> assert false in - match decl with - | Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) -> + match an with + | CTL.Decl (Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) as decl) -> let if_decl_opt = Ast_utils.get_decl_opt_with_decl_ref impl_decl_info.oidi_class_interface in (match if_decl_opt with | Some d when is_ck_context context decl -> check_interface d - | _ -> None) - | _ -> assert false + | _ -> CTL.False, None) + | _ -> CTL.False, None let in_ck_class (context: CLintersContext.context) = Option.map_default is_component_or_controller_descendant_impl false context.current_objc_impl @@ -247,7 +247,7 @@ let in_ck_class (context: CLintersContext.context) = relies on other threads (dispatch_sync). Other side-effects, like reading of global variables, is not checked by this analyzer, although still an infraction of the rule. *) -let rec component_initializer_with_side_effects_advice +let rec _component_initializer_with_side_effects_advice (context: CLintersContext.context) call_stmt = let condition = in_ck_class context @@ -258,7 +258,7 @@ let rec component_initializer_with_side_effects_advice if condition then match call_stmt with | Clang_ast_t.ImplicitCastExpr (_, stmt :: _, _, _) -> - component_initializer_with_side_effects_advice context stmt + _component_initializer_with_side_effects_advice context stmt | Clang_ast_t.DeclRefExpr (_, _, _, decl_ref_expr_info) -> let refs = [decl_ref_expr_info.drti_decl_ref; decl_ref_expr_info.drti_found_decl_ref] in @@ -266,15 +266,23 @@ let rec component_initializer_with_side_effects_advice | Some "dispatch_after" | Some "dispatch_async" | Some "dispatch_sync" -> - Some { + CTL.True, Some { CIssue.issue = CIssue.Component_initializer_with_side_effects; CIssue.description = "No Side-effects"; CIssue.suggestion = Some "Your +new method should not modify any \ global variables or global state."; CIssue.loc = CFrontend_checkers.location_from_stmt context call_stmt } - | _ -> None) + | _ -> + CTL.False, None) | _-> - None + CTL.False, None else - None + CTL.False, None + +let component_initializer_with_side_effects_advice + (context: CLintersContext.context) an = + match an with + | CTL.Stmt (CallExpr (_, called_func_stmt :: _, _)) -> + _component_initializer_with_side_effects_advice context called_func_stmt + | _ -> CTL.False, None (* only to be called in CallExpr *) diff --git a/infer/src/clang/ComponentKit.mli b/infer/src/clang/ComponentKit.mli index 5e2a18602..3e9240b72 100644 --- a/infer/src/clang/ComponentKit.mli +++ b/infer/src/clang/ComponentKit.mli @@ -15,16 +15,16 @@ val contains_ck_impl : Clang_ast_t.decl list -> bool val mutable_local_vars_advice : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option val component_factory_function_advice : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option val component_with_unconventional_superclass_advice : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option val component_with_multiple_factory_methods_advice : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option val component_initializer_with_side_effects_advice : - CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option diff --git a/infer/src/clang/cFrontend_checkers.ml b/infer/src/clang/cFrontend_checkers.ml index d41fd9496..d25bff8a4 100644 --- a/infer/src/clang/cFrontend_checkers.ml +++ b/infer/src/clang/cFrontend_checkers.ml @@ -36,15 +36,24 @@ let location_from_decl lctx dec = CLocation.get_sil_location_from_range lctx.CLintersContext.translation_unit_context info.Clang_ast_t.di_source_range true -let decl_name dec = - match Clang_ast_proj.get_named_decl_tuple dec with - | Some (_, n) -> n.Clang_ast_t.ni_name - | None -> "" +let location_from_an lcxt an = + match an with + | CTL.Stmt st -> location_from_stmt lcxt st + | CTL.Decl d -> location_from_decl lcxt d -let ivar_name stmt = + +let decl_name_from_an an = + match an with + | CTL.Decl dec -> + (match Clang_ast_proj.get_named_decl_tuple dec with + | Some (_, n) -> n.Clang_ast_t.ni_name + | None -> "") + | _ -> "" + +let ivar_name an = let open Clang_ast_t in - match stmt with - | ObjCIvarRefExpr (_, _, _, rei) -> + match an with + | CTL.Stmt (ObjCIvarRefExpr (_, _, _, rei)) -> let dr_ref = rei.ovrei_decl_ref in let ivar_pointer = dr_ref.dr_decl_pointer in (match Ast_utils.get_decl ivar_pointer with @@ -53,6 +62,15 @@ let ivar_name stmt = | _ -> "") | _ -> "" +let var_descs_name an = + let capt_refs = match an with + | CTL.Stmt (Clang_ast_t.BlockExpr (_, _ , _, decl)) -> + Predicates.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 + (* (is_CallExpr /\ not call_function_named) || is_CXXTemporaryObjectExpr || is_CXXMemberCallExpr @@ -75,7 +93,7 @@ let ctl_makes_an_expensive_call () = ET([ObjCMethodDecl][->Body] EF remove_observer) Or EH([ObjCImplementationDecl, ObjCProtocolDecl] EF remove_observer) *) -let ctl_ns_notification lctx decl = +let ctl_ns_notification_warning lctx an = let open CTL in let exists_method_calling_addObserver = EF (None, (Atomic ("call_method", ["addObserver:selector:name:object:"]))) in @@ -97,20 +115,21 @@ let ctl_ns_notification lctx decl = ET(["ObjCImplementationDecl"; "ObjCProtocolDecl"], None, Or(remove_observer_in_method , EH(["ObjCImplementationDecl"; "ObjCProtocolDecl"], remove_observer_in_method))) in - let condition = Not (Implies (eventually_addObserver, eventually_removeObserver)) in + let condition = InNode (["ObjCImplementationDecl"; "ObjCProtocolDecl"], + Not (Implies (eventually_addObserver, eventually_removeObserver))) in let issue_desc = { CIssue.issue = CIssue.Registered_observer_being_deallocated; CIssue.description = Localise.registered_observer_being_deallocated_str CFrontend_config.self; CIssue.suggestion = Some "Consider removing the object from the notification center before its deallocation."; - CIssue.loc = location_from_decl lctx decl; + CIssue.loc = location_from_an lctx an; } in - condition, issue_desc + condition, Some issue_desc (* BAD_POINTER_COMPARISON: Fires whenever a NSNumber is dangerously coerced to a boolean in a comparison *) -let ctl_bad_pointer_comparison_warning lctx stmt = +let ctl_bad_pointer_comparison_warning lctx an = let open CTL in let is_binop = Atomic ("is_stmt", ["BinaryOperator"]) in let is_binop_eq = Atomic ("is_binop_with_kind", ["EQ"]) in @@ -127,8 +146,9 @@ 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 = ETX (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], Some Cond, - EU (None, p', is_nsnumber)) in + let etx = ETX (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], Some Cond, + EU (None, p', is_nsnumber)) in + let condition = InNode (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], etx) in let issue_desc = { CIssue. issue = CIssue.Bad_pointer_comparison; @@ -137,12 +157,12 @@ let ctl_bad_pointer_comparison_warning lctx stmt = Some ("Did you mean to compare against the unboxed value instead? " ^ "Please either explicitly compare the NSNumber instance to nil, " ^ "or use one of the NSNumber accessors before the comparison."); - loc = location_from_stmt lctx stmt + loc = location_from_an lctx an } in - condition, issue_desc + condition, Some issue_desc (* name_contains_delegate AND not name_contains_queue AND is_strong_property *) -let ctl_strong_delegate lctx dec = +let ctl_strong_delegate_warning lctx an = let open CTL in let name_contains_delegate = Atomic ("property_name_contains_word", ["delegate"]) in @@ -150,22 +170,22 @@ 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 = ET (["ObjCPropertyDecl"], None, And (name_contains_delegate, - And (name_does_not_contains_queue, - is_strong_property))) in + let condition = InNode (["ObjCPropertyDecl"], 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 - "Property or ivar %s declared strong" (decl_name dec); + "Property or ivar %s declared strong" (decl_name_from_an an); CIssue.suggestion = Some "In general delegates should be declared weak or assign"; - CIssue.loc = location_from_decl lctx dec + CIssue.loc = location_from_an lctx an } in - condition, issue_desc + condition, Some issue_desc (* (is_ObjC || is_Objc++) /\ is_global_var /\ not is_const_var /\ ET([VarDecl][->InitExpr] EF ctl_makes_an_expensive_call) *) -let ctl_global_var_init_with_calls_warning lctx decl = +let ctl_global_var_init_with_calls_warning lctx an = let open CTL in let ctl_is_global_var = And (And (Atomic ("is_objc_extension", []), Atomic ("is_global_var", [])), @@ -173,125 +193,70 @@ let ctl_global_var_init_with_calls_warning lctx decl = let ctl_is_initialized_with_expensive_call = ET(["VarDecl"], Some InitExpr, EF (None, (ctl_makes_an_expensive_call ()))) in let condition = - ET (["VarDecl"], None, And (ctl_is_global_var, ctl_is_initialized_with_expensive_call)) in + InNode (["VarDecl"], 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 "Global variable %s is initialized using a function or method call" - (decl_name decl); + (decl_name_from_an an); CIssue.suggestion = Some "If the function/method call is expensive, it can affect the starting time of the app."; - CIssue.loc = location_from_decl lctx decl + CIssue.loc = location_from_an lctx an } in - condition, issue_desc + condition, Some issue_desc (* is_assign_property AND is_property_pointer_type *) -let ctl_assign_pointer_warning lctx decl = +let ctl_assign_pointer_warning lctx an = let open CTL in - let condition = ET(["ObjCPropertyDecl"], None, - And (Atomic ("is_assign_property", []), - Atomic ("is_property_pointer_type", []))) in + let condition = InNode(["ObjCPropertyDecl"], + And (Atomic ("is_assign_property", []), + Atomic ("is_property_pointer_type", []))) in let issue_desc = { CIssue.issue = CIssue.Assign_pointer_warning; CIssue.description = Printf.sprintf "Property `%s` is a pointer type marked with the `assign` attribute" - (decl_name decl); + (decl_name_from_an an); CIssue.suggestion = Some "Use a different attribute like `strong` or `weak`."; - CIssue.loc = location_from_decl lctx decl + CIssue.loc = location_from_an lctx an } in - condition, issue_desc + condition, Some issue_desc (* not context_in_synchronized_block /\ not is_method_property_accessor_of_ivar /\ not is_objc_constructor /\ not is_objc_dealloc *) -let ctl_direct_atomic_property_access_warning lctx stmt = +let ctl_direct_atomic_property_access_warning lctx an = let open CTL 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 condition = InNode (["ObjCIvarRefExpr"], + 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 - "Direct access to ivar %s of an atomic property" (ivar_name stmt); + "Direct access to ivar %s of an atomic property" (ivar_name an); CIssue.suggestion = Some "Accessing an ivar of an atomic property makes the property nonatomic"; - CIssue.loc = location_from_stmt lctx stmt + CIssue.loc = location_from_an lctx an } in - condition, issue_desc + condition, Some issue_desc -let ctl_captured_cxx_ref_in_objc_block_warning lctx stmt = +let ctl_captured_cxx_ref_in_objc_block_warning lctx an = (* Fire if the list of captured references is not empty *) let open CTL in - let condition = ET (["BlockDecl"], None, Atomic ("captures_cxx_references", [])) in + let condition = InNode (["BlockDecl"], Atomic ("captures_cxx_references", [])) in let issue_desc = { CIssue.issue = CIssue.Cxx_reference_captured_in_objc_block; CIssue.description = Printf.sprintf "C++ Reference variable(s) %s captured by Objective-C block" - (Predicates.var_descs_name stmt); + (var_descs_name an); CIssue.suggestion = Some ("C++ References are unmanaged and may be invalid " ^ "by the time the block executes."); - CIssue.loc = match stmt with - | Clang_ast_t.BlockExpr (_, _ , _, decl) -> location_from_decl lctx decl - | _ -> location_from_stmt lctx stmt; + CIssue.loc = match an with + | Stmt (Clang_ast_t.BlockExpr (_, _ , _, decl)) -> location_from_an lctx (Decl decl) + | _ -> location_from_an lctx an; } in - condition, issue_desc - -(* === Warnings on properties === *) - -(* Assing Pointer Warning: a property with a pointer type should not be declared `assign` *) -let assign_pointer_warning lctx decl = - let open CTL in - let condition, issue_desc = ctl_assign_pointer_warning lctx decl in - if CTL.eval_formula condition (Decl decl) lctx then - Some issue_desc - else None - -(* Strong Delegate Warning: a property with name delegate should not be declared strong *) -let strong_delegate_warning lctx decl = - let condition, issue_desc = ctl_strong_delegate lctx decl in - if CTL.eval_formula condition (Decl decl) lctx then - Some issue_desc - else None - -(* GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL warning: *) -(* a global variable initialization should not *) -(* contain calls to functions or methods as these can be expensive an delay the starting time *) -(* of an app *) -let global_var_init_with_calls_warning lctx decl = - let condition, issue_desc = ctl_global_var_init_with_calls_warning lctx decl in - if CTL.eval_formula condition (CTL.Decl decl) lctx then - Some issue_desc - else None - -(* Direct Atomic Property access: - a property declared atomic should not be accessed directly via its ivar *) -let direct_atomic_property_access_warning lctx stmt = - let condition, issue_desc = ctl_direct_atomic_property_access_warning lctx stmt in - if CTL.eval_formula condition (CTL.Stmt stmt) lctx then - Some issue_desc - else None - -(* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references - should not be captured in blocks. *) -let captured_cxx_ref_in_objc_block_warning lctx stmt = - let condition, issue_desc = ctl_captured_cxx_ref_in_objc_block_warning lctx stmt in - if CTL.eval_formula condition (CTL.Stmt stmt) lctx then - Some issue_desc - else None - -let checker_NSNotificationCenter lctx dec = - let condition, issue_desc = ctl_ns_notification lctx dec in - if CTL.eval_formula condition (CTL.Decl dec) lctx then - Some issue_desc - else None - -let bad_pointer_comparison_warning lctx stmt = - let condition, issue_desc = ctl_bad_pointer_comparison_warning lctx stmt in - if CTL.eval_formula condition (CTL.Stmt stmt) lctx then - Some issue_desc - else None + condition, Some issue_desc diff --git a/infer/src/clang/cFrontend_checkers.mli b/infer/src/clang/cFrontend_checkers.mli index c394d65b2..164433697 100644 --- a/infer/src/clang/cFrontend_checkers.mli +++ b/infer/src/clang/cFrontend_checkers.mli @@ -12,36 +12,36 @@ open! Utils (* === Warnings on properties === *) (* Strong Delegate Warning: a property with name delegate should not be declared strong *) -val strong_delegate_warning : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option +val ctl_strong_delegate_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option (* Assing Pointer Warning: a property with a pointer type should not be declared `assign` *) -val assign_pointer_warning : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option +val ctl_assign_pointer_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option (* Direct Atomic Property access: a property declared atomic should not be accesses directly via its iva *) -val direct_atomic_property_access_warning : - CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option +val ctl_direct_atomic_property_access_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option (* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references should not be captured in blocks. *) -val captured_cxx_ref_in_objc_block_warning : - CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option +val ctl_captured_cxx_ref_in_objc_block_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option -val bad_pointer_comparison_warning : - CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option +val ctl_bad_pointer_comparison_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option (* REGISTERED_OBSERVER_BEING_DEALLOCATED: an object is registered in a notification center but not removed before deallocation *) -val checker_NSNotificationCenter : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option +val ctl_ns_notification_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option (* GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL warning: a global variable initialization should not *) (* contain calls to functions or methods as these can be expensive an delay the starting time *) (* of a program *) -val global_var_init_with_calls_warning : - CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option +val ctl_global_var_init_with_calls_warning : + CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option val location_from_stmt : CLintersContext.context -> Clang_ast_t.stmt -> Location.t diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index cd9220fa3..4002aebef 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -49,7 +49,7 @@ let parse_ctl_file filename = let rec do_frontend_checks_stmt (context:CLintersContext.context) stmt = let open Clang_ast_t in - let context' = CFrontend_errors.run_frontend_checkers_on_stmt context stmt in + let context' = CFrontend_errors.run_frontend_checkers_on_an context (CTL.Stmt stmt) in let do_all_checks_on_stmts stmt = (match stmt with | DeclStmt (_, _, decl_list) -> @@ -102,7 +102,7 @@ and do_frontend_checks_decl (context: CLintersContext.context) decl = | None -> ()); context' | _ -> context) in - let context'' = CFrontend_errors.run_frontend_checkers_on_decl context' decl in + let context'' = CFrontend_errors.run_frontend_checkers_on_an context' (CTL.Decl decl) in let context_with_orig_current_method = {context'' with CLintersContext.current_method = context.current_method } in match Clang_ast_proj.get_decl_context_tuple decl with diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index 0a2276a6e..9e04ccf4a 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -12,68 +12,25 @@ open! Utils open CFrontend_utils (* List of checkers on properties *) -let property_checkers_list = [CFrontend_checkers.strong_delegate_warning; - CFrontend_checkers.assign_pointer_warning;] - -(* Invocation of checker belonging to property_checker_list *) -let checkers_for_property decl checker context = - checker context decl +let decl_checkers_list = [CFrontend_checkers.ctl_strong_delegate_warning; + CFrontend_checkers.ctl_assign_pointer_warning; + CFrontend_checkers.ctl_ns_notification_warning; + CFrontend_checkers.ctl_global_var_init_with_calls_warning; + ComponentKit.component_with_unconventional_superclass_advice; + ComponentKit.mutable_local_vars_advice; + ComponentKit.component_factory_function_advice; + ComponentKit.component_with_multiple_factory_methods_advice;] (* List of checkers on ivar access *) -let ivar_access_checker_list = [CFrontend_checkers.direct_atomic_property_access_warning] - -(* Invocation of checker belonging to ivar_access_checker_list *) -let checkers_for_ivar stmt checker context = - checker context stmt - -(* List of checkers for captured vars in objc blocks *) -let captured_vars_checker_list = [CFrontend_checkers.captured_cxx_ref_in_objc_block_warning] - -(* Invocation of checker belonging to captured_vars_checker_list *) -let checkers_for_capture_vars stmt checker context = - checker context stmt - -(* List of checkers on ObjCProtocol decls *) -let objc_protocol_checker_list = [CFrontend_checkers.checker_NSNotificationCenter] - -(* Invocation of checker belonging to objc_protocol_checker_list *) -let checkers_for_objc_protocol decl checker context = - checker context decl +let stmt_checkers_list = [CFrontend_checkers.ctl_direct_atomic_property_access_warning; + CFrontend_checkers.ctl_captured_cxx_ref_in_objc_block_warning; + CFrontend_checkers.ctl_bad_pointer_comparison_warning; + ComponentKit.component_initializer_with_side_effects_advice;] -(* List of checkers running on ObjCImpl decls *) -let objc_impl_checker_list = [CFrontend_checkers.checker_NSNotificationCenter; - ComponentKit.component_with_multiple_factory_methods_advice; - ComponentKit.component_with_unconventional_superclass_advice] -(* Invocation of checker belonging to objc_impl_checker_list *) -let checkers_for_objc_impl decl checker context = - checker context decl -let call_expr_checker_list = [ComponentKit.component_initializer_with_side_effects_advice] -(* Invocation of checker belonging to call_expr_checker_list *) -let checkers_for_call_expr stmt checker context = - checker context stmt -(* List of checkers on variables *) -let var_checker_list = [CFrontend_checkers.global_var_init_with_calls_warning; - ComponentKit.mutable_local_vars_advice] - -(* Invocation of checker belonging to var_checker_list *) -let checker_for_var dec checker context = - checker context dec - -(* List of checkers on if-statement *) -let if_stmt_checker_list = [CFrontend_checkers.bad_pointer_comparison_warning] - -(* Invocation of checker belonging to if_stmt_checker_list *) -let checker_for_if_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 = - checker context decl let get_err_log translation_unit_context method_decl_opt = let procname = match method_decl_opt with @@ -97,75 +54,25 @@ let log_frontend_issue translation_unit_context method_decl_opt key issue_desc = Reporting.log_issue_from_errlog err_kind errlog exn ~loc ~ltr:trace ~node_id:(0, key) -(* General invocation function for checkers - Takes - 1. f a particular way to apply a checker, it's a partial function - 2. context - 3. the list of checkers to be applied *) -let invoke_set_of_checkers f context key checkers = +let invoke_set_of_checkers_an an context = + let checkers, key = match an with + | CTL.Decl dec -> decl_checkers_list, Ast_utils.generate_key_decl dec + | CTL.Stmt st -> stmt_checkers_list, Ast_utils.generate_key_stmt st in IList.iter (fun checker -> - match f checker context with - | Some issue_desc -> - log_frontend_issue context.CLintersContext.translation_unit_context - context.CLintersContext.current_method key issue_desc - | None -> ()) checkers + let condition, issue_desc_opt = checker context an in + match CTL.eval_formula condition an context, issue_desc_opt with + | true, Some issue_desc -> log_frontend_issue context.CLintersContext.translation_unit_context + context.CLintersContext.current_method key issue_desc + | _, _ -> ()) checkers -let run_frontend_checkers_on_stmt context instr = - let open Clang_ast_t in - match instr with - | ObjCIvarRefExpr _ -> - let call_checker_for_ivar = checkers_for_ivar instr in - let key = Ast_utils.generate_key_stmt instr in - invoke_set_of_checkers - call_checker_for_ivar context key ivar_access_checker_list; - context - | BlockExpr _ -> - let call_captured_vars_checker = checkers_for_capture_vars instr in - let key = Ast_utils.generate_key_stmt instr in - invoke_set_of_checkers call_captured_vars_checker context key - captured_vars_checker_list; - context - | 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 - | 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 - invoke_set_of_checkers call_checker context key call_expr_checker_list; - context - | ObjCAtSynchronizedStmt _ -> - { context with CLintersContext.in_synchronized_block = true } - | _ -> context -let run_frontend_checkers_on_decl (context: CLintersContext.context) dec = +let run_frontend_checkers_on_an (context: CLintersContext.context) an = let open Clang_ast_t in - match dec with - | ObjCImplementationDecl _ -> - let call_objc_impl_checker = checkers_for_objc_impl dec in - let key = Ast_utils.generate_key_decl dec in - let context' = {context with current_objc_impl = Some dec} in - invoke_set_of_checkers call_objc_impl_checker context' key objc_impl_checker_list; - context' - | ObjCProtocolDecl _ -> - let call_objc_protocol_checker = checkers_for_objc_protocol dec in - let key = Ast_utils.generate_key_decl dec in - invoke_set_of_checkers call_objc_protocol_checker context key objc_protocol_checker_list; - context - | VarDecl _ -> - let call_var_checker = checker_for_var dec in - let key = Ast_utils.generate_key_decl dec in - invoke_set_of_checkers call_var_checker context key var_checker_list; - context - | FunctionDecl _ -> - let call_function_decl_checker = checker_for_function_decl dec in - let key = Ast_utils.generate_key_decl dec in - invoke_set_of_checkers call_function_decl_checker context key function_decl_checker_list; - context - | ObjCPropertyDecl _ -> - let call_property_checker = checkers_for_property dec in - let key = Ast_utils.generate_key_decl dec in - invoke_set_of_checkers call_property_checker context key property_checkers_list; - context - | _ -> context + let context' = match an with + | CTL.Decl (ObjCImplementationDecl _ as dec) -> + {context with current_objc_impl = Some dec} + | CTL.Stmt (ObjCAtSynchronizedStmt _ )-> + { context with CLintersContext.in_synchronized_block = true } + | _ -> context in + invoke_set_of_checkers_an an context'; + context' diff --git a/infer/src/clang/cFrontend_errors.mli b/infer/src/clang/cFrontend_errors.mli index 10657c350..5929b0a6a 100644 --- a/infer/src/clang/cFrontend_errors.mli +++ b/infer/src/clang/cFrontend_errors.mli @@ -12,10 +12,6 @@ open! Utils (* Module for warnings detected at translation time by the frontend *) -(* Run frontend checkers on a statement *) -val run_frontend_checkers_on_stmt : - CLintersContext.context -> Clang_ast_t.stmt -> CLintersContext.context - -(* Run frontend checkers on a declaration *) -val run_frontend_checkers_on_decl : CLintersContext.context -> Clang_ast_t.decl -> - CLintersContext.context +(* Run frontend checkers on an AST node *) +val run_frontend_checkers_on_an : + CLintersContext.context -> CTL.ast_node -> CLintersContext.context diff --git a/infer/src/clang/predicates.ml b/infer/src/clang/predicates.ml index f3c0a4e82..3ce155dee 100644 --- a/infer/src/clang/predicates.ml +++ b/infer/src/clang/predicates.ml @@ -41,14 +41,6 @@ let captured_variables_cxx_ref dec = | _ -> [] in IList.fold_left capture_var_is_cxx_ref [] captured_vars -let var_descs_name stmt = - 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 type t = string * string list (* (name, [param1,...,paramK]) *) diff --git a/infer/src/clang/predicates.mli b/infer/src/clang/predicates.mli index cf4596bdf..0767e9d4c 100644 --- a/infer/src/clang/predicates.mli +++ b/infer/src/clang/predicates.mli @@ -9,7 +9,7 @@ type t = string * string list (* (name, [param1,...,paramK]) *) -val var_descs_name : Clang_ast_t.stmt -> string (* Helper function *) +val captured_variables_cxx_ref : Clang_ast_t.decl -> Clang_ast_t.named_decl_info list val call_method : string -> Clang_ast_t.stmt -> bool