Removing the dispatcher for linters.

Reviewed By: dulmarod

Differential Revision: D4182551

fbshipit-source-id: af7c88e
master
Dino Distefano 8 years ago committed by Facebook Github Bot
parent 4512fcd8ef
commit 0ed033a32e

@ -64,7 +64,7 @@ and contains_ck_impl decl_list =
const int *z; const int *z;
const NSString *y; 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 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 let typ_opt = Ast_utils.get_desugared_type qual_type.qt_type_ptr in
match (typ_opt : Clang_ast_t.c_type option) with 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 IList.mem string_equal ndi.ni_name objc_whitelist
| _ -> false in | _ -> false in
match decl with match an with
| Clang_ast_t.VarDecl(decl_info, named_decl_info, qual_type, _) -> | 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 let is_const_ref = match Ast_utils.get_type qual_type.qt_type_ptr with
| Some LValueReferenceType (_, {Clang_ast_t.qt_is_const}) -> | Some LValueReferenceType (_, {Clang_ast_t.qt_is_const}) ->
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 (is_of_whitelisted_type qual_type)
&& not decl_info.di_is_implicit in && not decl_info.di_is_implicit in
if condition then if condition then
Some { CTL.True, Some {
CIssue.issue = CIssue.Mutable_local_variable_in_component_file; CIssue.issue = CIssue.Mutable_local_variable_in_component_file;
CIssue.description = "Local variable '" ^ named_decl_info.ni_name CIssue.description = "Local variable '" ^ named_decl_info.ni_name
^ "' should be const to avoid reassignment"; ^ "' should be const to avoid reassignment";
CIssue.suggestion = Some "Add a const (after the asterisk for pointer types)."; CIssue.suggestion = Some "Add a const (after the asterisk for pointer types).";
CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info
} }
else None else CTL.False, None
| _ -> assert false (* Should only be called with a VarDecl *) | _ -> CTL.False, None (* Should only be called with a VarDecl *)
(** Catches functions that should be composite components. (** Catches functions that should be composite components.
http://componentkit.org/docs/break-out-composites.html http://componentkit.org/docs/break-out-composites.html
Any static function that returns a subclass of CKComponent will be flagged. *) 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 = let is_component_if decl =
Ast_utils.is_objc_if_descendant decl [CFrontend_config.ckcomponent_cl] in Ast_utils.is_objc_if_descendant decl [CFrontend_config.ckcomponent_cl] in
match decl with match an with
| Clang_ast_t.FunctionDecl (decl_info, _, (qual_type: Clang_ast_t.qual_type), _) -> | CTL.Decl (Clang_ast_t.FunctionDecl (decl_info, _, (qual_type: Clang_ast_t.qual_type), _) as decl) ->
let objc_interface = let objc_interface =
Ast_utils.type_ptr_to_objc_interface qual_type.qt_type_ptr in Ast_utils.type_ptr_to_objc_interface qual_type.qt_type_ptr in
let condition = let condition =
is_ck_context context decl && is_component_if objc_interface in is_ck_context context decl && is_component_if objc_interface in
if condition then if condition then
Some { CTL.True, Some {
CIssue.issue = CIssue.Component_factory_function; CIssue.issue = CIssue.Component_factory_function;
CIssue.description = "Break out composite components"; CIssue.description = "Break out composite components";
CIssue.suggestion = Some ( CIssue.suggestion = Some (
@ -133,13 +133,13 @@ let component_factory_function_advice context decl =
); );
CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info
} }
else None else CTL.False, None
| _ -> assert false (* Should only be called with FunctionDecl *) | _ -> CTL.False, None (* Should only be called with FunctionDecl *)
(** Components should not inherit from each other. They should instead (** Components should not inherit from each other. They should instead
inherit from CKComponent, CKCompositeComponent, or inherit from CKComponent, CKCompositeComponent, or
CKStatefulViewComponent. (Similar rule applies to component controllers.) *) 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 = let check_interface if_decl =
match if_decl with match if_decl with
| Clang_ast_t.ObjCInterfaceDecl (_, _, _, _, _) -> | Clang_ast_t.ObjCInterfaceDecl (_, _, _, _, _) ->
@ -164,7 +164,7 @@ let component_with_unconventional_superclass_advice context decl =
is_component_or_controller_if (Some if_decl) is_component_or_controller_if (Some if_decl)
&& not has_conventional_superclass in && not has_conventional_superclass in
if condition then if condition then
Some { CTL.True, Some {
CIssue.issue = CIssue.Component_with_unconventional_superclass; CIssue.issue = CIssue.Component_with_unconventional_superclass;
CIssue.description = "Never Subclass Components"; CIssue.description = "Never Subclass Components";
CIssue.suggestion = Some ( 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 CIssue.loc = CFrontend_checkers.location_from_decl context if_decl
} }
else else
None CTL.False, None
else else
None CTL.False, None
| _ -> assert false in | _ -> assert false in
match decl with match an with
| Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) -> | CTL.Decl (Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) as decl) ->
let if_decl_opt = let if_decl_opt =
Ast_utils.get_decl_opt_with_decl_ref impl_decl_info.oidi_class_interface in 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 if Option.is_some if_decl_opt && is_ck_context context decl then
check_interface (Option.get if_decl_opt) check_interface (Option.get if_decl_opt)
else else
None CTL.False, None
| _ -> assert false | _ -> CTL.False, None
(** Components should only have one factory method. (** 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 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 there would be factory methods that aren't exposed outside of a class is
not useful if there's only one public factory method. *) 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 let is_unavailable_attr attr = match attr with
| Clang_ast_t.UnavailableAttr _ -> true | Clang_ast_t.UnavailableAttr _ -> true
| _ -> false in | _ -> false in
@ -214,7 +214,7 @@ let component_with_multiple_factory_methods_advice context decl =
| Clang_ast_t.ObjCInterfaceDecl (decl_info, _, decls, _, _) -> | Clang_ast_t.ObjCInterfaceDecl (decl_info, _, decls, _, _) ->
let factory_methods = IList.filter (is_available_factory_method if_decl) decls in let factory_methods = IList.filter (is_available_factory_method if_decl) decls in
if (IList.length factory_methods) > 1 then if (IList.length factory_methods) > 1 then
Some { CTL.True, Some {
CIssue.issue = CIssue.Component_with_multiple_factory_methods; CIssue.issue = CIssue.Component_with_multiple_factory_methods;
CIssue.description = "Avoid Overrides"; CIssue.description = "Avoid Overrides";
CIssue.suggestion = 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 CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info
} }
else else
None CTL.False, None
| _ -> assert false in | _ -> assert false in
match decl with match an with
| Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) -> | CTL.Decl (Clang_ast_t.ObjCImplementationDecl (_, _, _, _, impl_decl_info) as decl) ->
let if_decl_opt = let if_decl_opt =
Ast_utils.get_decl_opt_with_decl_ref impl_decl_info.oidi_class_interface in Ast_utils.get_decl_opt_with_decl_ref impl_decl_info.oidi_class_interface in
(match if_decl_opt with (match if_decl_opt with
| Some d when is_ck_context context decl -> check_interface d | Some d when is_ck_context context decl -> check_interface d
| _ -> None) | _ -> CTL.False, None)
| _ -> assert false | _ -> CTL.False, None
let in_ck_class (context: CLintersContext.context) = let in_ck_class (context: CLintersContext.context) =
Option.map_default is_component_or_controller_descendant_impl false context.current_objc_impl 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 relies on other threads (dispatch_sync). Other side-effects, like reading
of global variables, is not checked by this analyzer, although still an of global variables, is not checked by this analyzer, although still an
infraction of the rule. *) 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 = (context: CLintersContext.context) call_stmt =
let condition = let condition =
in_ck_class context in_ck_class context
@ -258,7 +258,7 @@ let rec component_initializer_with_side_effects_advice
if condition then if condition then
match call_stmt with match call_stmt with
| Clang_ast_t.ImplicitCastExpr (_, stmt :: _, _, _) -> | 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) -> | Clang_ast_t.DeclRefExpr (_, _, _, decl_ref_expr_info) ->
let refs = [decl_ref_expr_info.drti_decl_ref; let refs = [decl_ref_expr_info.drti_decl_ref;
decl_ref_expr_info.drti_found_decl_ref] in 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_after"
| Some "dispatch_async" | Some "dispatch_async"
| Some "dispatch_sync" -> | Some "dispatch_sync" ->
Some { CTL.True, Some {
CIssue.issue = CIssue.Component_initializer_with_side_effects; CIssue.issue = CIssue.Component_initializer_with_side_effects;
CIssue.description = "No Side-effects"; CIssue.description = "No Side-effects";
CIssue.suggestion = Some "Your +new method should not modify any \ CIssue.suggestion = Some "Your +new method should not modify any \
global variables or global state."; global variables or global state.";
CIssue.loc = CFrontend_checkers.location_from_stmt context call_stmt CIssue.loc = CFrontend_checkers.location_from_stmt context call_stmt
} }
| _ -> None) | _ ->
CTL.False, None)
| _-> | _->
None CTL.False, None
else 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 *)

@ -15,16 +15,16 @@
val contains_ck_impl : Clang_ast_t.decl list -> bool val contains_ck_impl : Clang_ast_t.decl list -> bool
val mutable_local_vars_advice : 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 : 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 : 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 : 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 : 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

@ -36,15 +36,24 @@ let location_from_decl lctx dec =
CLocation.get_sil_location_from_range lctx.CLintersContext.translation_unit_context CLocation.get_sil_location_from_range lctx.CLintersContext.translation_unit_context
info.Clang_ast_t.di_source_range true info.Clang_ast_t.di_source_range true
let decl_name dec = let location_from_an lcxt an =
match Clang_ast_proj.get_named_decl_tuple dec with match an with
| Some (_, n) -> n.Clang_ast_t.ni_name | CTL.Stmt st -> location_from_stmt lcxt st
| None -> "" | 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 let open Clang_ast_t in
match stmt with match an with
| ObjCIvarRefExpr (_, _, _, rei) -> | CTL.Stmt (ObjCIvarRefExpr (_, _, _, rei)) ->
let dr_ref = rei.ovrei_decl_ref in let dr_ref = rei.ovrei_decl_ref in
let ivar_pointer = dr_ref.dr_decl_pointer in let ivar_pointer = dr_ref.dr_decl_pointer in
(match Ast_utils.get_decl ivar_pointer with (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_CallExpr /\ not call_function_named) ||
is_CXXTemporaryObjectExpr || is_CXXMemberCallExpr is_CXXTemporaryObjectExpr || is_CXXMemberCallExpr
@ -75,7 +93,7 @@ let ctl_makes_an_expensive_call () =
ET([ObjCMethodDecl][->Body] EF remove_observer) Or ET([ObjCMethodDecl][->Body] EF remove_observer) Or
EH([ObjCImplementationDecl, ObjCProtocolDecl] EF remove_observer) EH([ObjCImplementationDecl, ObjCProtocolDecl] EF remove_observer)
*) *)
let ctl_ns_notification lctx decl = let ctl_ns_notification_warning lctx an =
let open CTL in let open CTL in
let exists_method_calling_addObserver = let exists_method_calling_addObserver =
EF (None, (Atomic ("call_method", ["addObserver:selector:name:object:"]))) in EF (None, (Atomic ("call_method", ["addObserver:selector:name:object:"]))) in
@ -97,20 +115,21 @@ let ctl_ns_notification lctx decl =
ET(["ObjCImplementationDecl"; "ObjCProtocolDecl"], None, ET(["ObjCImplementationDecl"; "ObjCProtocolDecl"], None,
Or(remove_observer_in_method , Or(remove_observer_in_method ,
EH(["ObjCImplementationDecl"; "ObjCProtocolDecl"], remove_observer_in_method))) in 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 = { let issue_desc = {
CIssue.issue = CIssue.Registered_observer_being_deallocated; CIssue.issue = CIssue.Registered_observer_being_deallocated;
CIssue.description = CIssue.description =
Localise.registered_observer_being_deallocated_str CFrontend_config.self; Localise.registered_observer_being_deallocated_str CFrontend_config.self;
CIssue.suggestion = CIssue.suggestion =
Some "Consider removing the object from the notification center before its deallocation."; 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 } in
condition, issue_desc condition, Some issue_desc
(* BAD_POINTER_COMPARISON: Fires whenever a NSNumber is dangerously coerced to (* BAD_POINTER_COMPARISON: Fires whenever a NSNumber is dangerously coerced to
a boolean in a comparison *) 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 open CTL in
let is_binop = Atomic ("is_stmt", ["BinaryOperator"]) in let is_binop = Atomic ("is_stmt", ["BinaryOperator"]) in
let is_binop_eq = Atomic ("is_binop_with_kind", ["EQ"]) 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 = 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 p' = And (Not is_binop_neq, p) in
let condition = ETX (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], Some Cond, let etx = ETX (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], Some Cond,
EU (None, p', is_nsnumber)) in EU (None, p', is_nsnumber)) in
let condition = InNode (["IfStmt"; "ForStmt"; "WhileStmt"; "ConditionalOperator"], etx) in
let issue_desc = let issue_desc =
{ CIssue. { CIssue.
issue = CIssue.Bad_pointer_comparison; 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? " ^ Some ("Did you mean to compare against the unboxed value instead? " ^
"Please either explicitly compare the NSNumber instance to nil, " ^ "Please either explicitly compare the NSNumber instance to nil, " ^
"or use one of the NSNumber accessors before the comparison."); "or use one of the NSNumber accessors before the comparison.");
loc = location_from_stmt lctx stmt loc = location_from_an lctx an
} in } in
condition, issue_desc condition, Some issue_desc
(* name_contains_delegate AND not name_contains_queue AND is_strong_property *) (* 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 open CTL in
let name_contains_delegate = let name_contains_delegate =
Atomic ("property_name_contains_word", ["delegate"]) in 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 Not(Atomic ("property_name_contains_word", ["queue"])) in
let is_strong_property = let is_strong_property =
Atomic("is_strong_property", []) in Atomic("is_strong_property", []) in
let condition = ET (["ObjCPropertyDecl"], None, And (name_contains_delegate, let condition = InNode (["ObjCPropertyDecl"], And (name_contains_delegate,
And (name_does_not_contains_queue, And (name_does_not_contains_queue,
is_strong_property))) in is_strong_property))) in
let issue_desc = { let issue_desc = {
CIssue.issue = CIssue.Strong_delegate_warning; CIssue.issue = CIssue.Strong_delegate_warning;
CIssue.description = Printf.sprintf 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.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 } in
condition, issue_desc condition, Some issue_desc
(* (is_ObjC || is_Objc++) /\ is_global_var /\ not is_const_var /\ (* (is_ObjC || is_Objc++) /\ is_global_var /\ not is_const_var /\
ET([VarDecl][->InitExpr] EF ctl_makes_an_expensive_call) 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 open CTL in
let ctl_is_global_var = let ctl_is_global_var =
And (And (Atomic ("is_objc_extension", []), Atomic ("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 = let ctl_is_initialized_with_expensive_call =
ET(["VarDecl"], Some InitExpr, EF (None, (ctl_makes_an_expensive_call ()))) in ET(["VarDecl"], Some InitExpr, EF (None, (ctl_makes_an_expensive_call ()))) in
let condition = 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 = { let issue_desc = {
CIssue.issue = CIssue.Global_variable_initialized_with_function_or_method_call; CIssue.issue = CIssue.Global_variable_initialized_with_function_or_method_call;
CIssue.description = Printf.sprintf CIssue.description = Printf.sprintf
"Global variable %s is initialized using a function or method call" "Global variable %s is initialized using a function or method call"
(decl_name decl); (decl_name_from_an an);
CIssue.suggestion = Some CIssue.suggestion = Some
"If the function/method call is expensive, it can affect the starting time of the app."; "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 } in
condition, issue_desc condition, Some issue_desc
(* is_assign_property AND is_property_pointer_type *) (* 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 open CTL in
let condition = ET(["ObjCPropertyDecl"], None, let condition = InNode(["ObjCPropertyDecl"],
And (Atomic ("is_assign_property", []), And (Atomic ("is_assign_property", []),
Atomic ("is_property_pointer_type", []))) in Atomic ("is_property_pointer_type", []))) in
let issue_desc = let issue_desc =
{ CIssue.issue = CIssue.Assign_pointer_warning; { CIssue.issue = CIssue.Assign_pointer_warning;
CIssue.description = CIssue.description =
Printf.sprintf Printf.sprintf
"Property `%s` is a pointer type marked with the `assign` attribute" "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.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 } in
condition, issue_desc condition, Some issue_desc
(* (*
not context_in_synchronized_block /\ not is_method_property_accessor_of_ivar not context_in_synchronized_block /\ not is_method_property_accessor_of_ivar
/\ not is_objc_constructor /\ not is_objc_dealloc /\ 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 open CTL in
let condition = ET (["ObjCIvarRefExpr"], None, let condition = InNode (["ObjCIvarRefExpr"],
And (And (And (And (Not (Atomic ("context_in_synchronized_block", [])), And (And (And (And (Not (Atomic ("context_in_synchronized_block", [])),
Atomic("is_ivar_atomic", [])), Atomic("is_ivar_atomic", [])),
Not (Atomic ("is_method_property_accessor_of_ivar", []))), Not (Atomic ("is_method_property_accessor_of_ivar", []))),
Not (Atomic ("is_objc_constructor", []))), Not (Atomic ("is_objc_constructor", []))),
Not (Atomic ("is_objc_dealloc", [])))) in Not (Atomic ("is_objc_dealloc", [])))) in
let issue_desc = { let issue_desc = {
CIssue.issue = CIssue.Direct_atomic_property_access; CIssue.issue = CIssue.Direct_atomic_property_access;
CIssue.description = Printf.sprintf 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 = CIssue.suggestion =
Some "Accessing an ivar of an atomic property makes the property nonatomic"; 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 } 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 *) (* Fire if the list of captured references is not empty *)
let open CTL in 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 = { let issue_desc = {
CIssue.issue = CIssue.Cxx_reference_captured_in_objc_block; CIssue.issue = CIssue.Cxx_reference_captured_in_objc_block;
CIssue.description = Printf.sprintf CIssue.description = Printf.sprintf
"C++ Reference variable(s) %s captured by Objective-C block" "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 " ^ CIssue.suggestion = Some ("C++ References are unmanaged and may be invalid " ^
"by the time the block executes."); "by the time the block executes.");
CIssue.loc = match stmt with CIssue.loc = match an with
| Clang_ast_t.BlockExpr (_, _ , _, decl) -> location_from_decl lctx decl | Stmt (Clang_ast_t.BlockExpr (_, _ , _, decl)) -> location_from_an lctx (Decl decl)
| _ -> location_from_stmt lctx stmt; | _ -> location_from_an lctx an;
} in } in
condition, issue_desc condition, Some 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

@ -12,36 +12,36 @@ open! Utils
(* === Warnings on properties === *) (* === Warnings on properties === *)
(* Strong Delegate Warning: a property with name delegate should not be declared strong *) (* Strong Delegate Warning: a property with name delegate should not be declared strong *)
val strong_delegate_warning : val ctl_strong_delegate_warning :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option 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` *) (* Assing Pointer Warning: a property with a pointer type should not be declared `assign` *)
val assign_pointer_warning : val ctl_assign_pointer_warning :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option
(* Direct Atomic Property access: (* Direct Atomic Property access:
a property declared atomic should not be accesses directly via its iva *) a property declared atomic should not be accesses directly via its iva *)
val direct_atomic_property_access_warning : val ctl_direct_atomic_property_access_warning :
CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option
(* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references (* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references
should not be captured in blocks. *) should not be captured in blocks. *)
val captured_cxx_ref_in_objc_block_warning : val ctl_captured_cxx_ref_in_objc_block_warning :
CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option
val bad_pointer_comparison_warning : val ctl_bad_pointer_comparison_warning :
CLintersContext.context -> Clang_ast_t.stmt -> CIssue.issue_desc option CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option
(* REGISTERED_OBSERVER_BEING_DEALLOCATED: an object is registered in a notification center (* REGISTERED_OBSERVER_BEING_DEALLOCATED: an object is registered in a notification center
but not removed before deallocation *) but not removed before deallocation *)
val checker_NSNotificationCenter : val ctl_ns_notification_warning :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option 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 *) (* 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 *) (* contain calls to functions or methods as these can be expensive an delay the starting time *)
(* of a program *) (* of a program *)
val global_var_init_with_calls_warning : val ctl_global_var_init_with_calls_warning :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option
val location_from_stmt : val location_from_stmt :
CLintersContext.context -> Clang_ast_t.stmt -> Location.t CLintersContext.context -> Clang_ast_t.stmt -> Location.t

@ -49,7 +49,7 @@ let parse_ctl_file filename =
let rec do_frontend_checks_stmt (context:CLintersContext.context) stmt = let rec do_frontend_checks_stmt (context:CLintersContext.context) stmt =
let open Clang_ast_t in 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 = let do_all_checks_on_stmts stmt =
(match stmt with (match stmt with
| DeclStmt (_, _, decl_list) -> | DeclStmt (_, _, decl_list) ->
@ -102,7 +102,7 @@ and do_frontend_checks_decl (context: CLintersContext.context) decl =
| None -> ()); | None -> ());
context' context'
| _ -> context) in | _ -> 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 = let context_with_orig_current_method =
{context'' with CLintersContext.current_method = context.current_method } in {context'' with CLintersContext.current_method = context.current_method } in
match Clang_ast_proj.get_decl_context_tuple decl with match Clang_ast_proj.get_decl_context_tuple decl with

@ -12,68 +12,25 @@ open! Utils
open CFrontend_utils open CFrontend_utils
(* List of checkers on properties *) (* List of checkers on properties *)
let property_checkers_list = [CFrontend_checkers.strong_delegate_warning; let decl_checkers_list = [CFrontend_checkers.ctl_strong_delegate_warning;
CFrontend_checkers.assign_pointer_warning;] CFrontend_checkers.ctl_assign_pointer_warning;
CFrontend_checkers.ctl_ns_notification_warning;
(* Invocation of checker belonging to property_checker_list *) CFrontend_checkers.ctl_global_var_init_with_calls_warning;
let checkers_for_property decl checker context = ComponentKit.component_with_unconventional_superclass_advice;
checker context decl ComponentKit.mutable_local_vars_advice;
ComponentKit.component_factory_function_advice;
ComponentKit.component_with_multiple_factory_methods_advice;]
(* List of checkers on ivar access *) (* List of checkers on ivar access *)
let ivar_access_checker_list = [CFrontend_checkers.direct_atomic_property_access_warning] let stmt_checkers_list = [CFrontend_checkers.ctl_direct_atomic_property_access_warning;
CFrontend_checkers.ctl_captured_cxx_ref_in_objc_block_warning;
(* Invocation of checker belonging to ivar_access_checker_list *) CFrontend_checkers.ctl_bad_pointer_comparison_warning;
let checkers_for_ivar stmt checker context = ComponentKit.component_initializer_with_side_effects_advice;]
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
(* 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 get_err_log translation_unit_context method_decl_opt =
let procname = match method_decl_opt with 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 Reporting.log_issue_from_errlog err_kind errlog exn ~loc ~ltr:trace
~node_id:(0, key) ~node_id:(0, key)
(* General invocation function for checkers let invoke_set_of_checkers_an an context =
Takes let checkers, key = match an with
1. f a particular way to apply a checker, it's a partial function | CTL.Decl dec -> decl_checkers_list, Ast_utils.generate_key_decl dec
2. context | CTL.Stmt st -> stmt_checkers_list, Ast_utils.generate_key_stmt st in
3. the list of checkers to be applied *)
let invoke_set_of_checkers f context key checkers =
IList.iter (fun checker -> IList.iter (fun checker ->
match f checker context with let condition, issue_desc_opt = checker context an in
| Some issue_desc -> match CTL.eval_formula condition an context, issue_desc_opt with
log_frontend_issue context.CLintersContext.translation_unit_context | true, Some issue_desc -> log_frontend_issue context.CLintersContext.translation_unit_context
context.CLintersContext.current_method key issue_desc context.CLintersContext.current_method key issue_desc
| None -> ()) checkers | _, _ -> ()) 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 let open Clang_ast_t in
match dec with let context' = match an with
| ObjCImplementationDecl _ -> | CTL.Decl (ObjCImplementationDecl _ as dec) ->
let call_objc_impl_checker = checkers_for_objc_impl dec in {context with current_objc_impl = Some dec}
let key = Ast_utils.generate_key_decl dec in | CTL.Stmt (ObjCAtSynchronizedStmt _ )->
let context' = {context with current_objc_impl = Some dec} in { context with CLintersContext.in_synchronized_block = true }
invoke_set_of_checkers call_objc_impl_checker context' key objc_impl_checker_list; | _ -> context in
context' invoke_set_of_checkers_an an context';
| ObjCProtocolDecl _ -> context'
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

@ -12,10 +12,6 @@ open! Utils
(* Module for warnings detected at translation time by the frontend *) (* Module for warnings detected at translation time by the frontend *)
(* Run frontend checkers on a statement *) (* Run frontend checkers on an AST node *)
val run_frontend_checkers_on_stmt : val run_frontend_checkers_on_an :
CLintersContext.context -> Clang_ast_t.stmt -> CLintersContext.context CLintersContext.context -> CTL.ast_node -> CLintersContext.context
(* Run frontend checkers on a declaration *)
val run_frontend_checkers_on_decl : CLintersContext.context -> Clang_ast_t.decl ->
CLintersContext.context

@ -41,14 +41,6 @@ let captured_variables_cxx_ref dec =
| _ -> [] in | _ -> [] in
IList.fold_left capture_var_is_cxx_ref [] captured_vars 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]) *) type t = string * string list (* (name, [param1,...,paramK]) *)

@ -9,7 +9,7 @@
type t = string * string list (* (name, [param1,...,paramK]) *) 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 val call_method : string -> Clang_ast_t.stmt -> bool

Loading…
Cancel
Save