Adding ability to get type of paramters.

Reviewed By: dulmarod

Differential Revision: D5069844

fbshipit-source-id: c591f76
master
Dino Distefano 8 years ago committed by Facebook Github Bot
parent 45aaa4da93
commit bdd2395be6

@ -47,9 +47,9 @@ let tag_name_of_node an =
let decl_ref_or_selector_name an =
match CTL.next_state_via_transition an (Some CTL.PointerToDecl) with
| Some (Ctl_parser_types.Decl ObjCMethodDecl _ as decl_an) ->
| [Ctl_parser_types.Decl ObjCMethodDecl _ as decl_an] ->
"The selector " ^ (Ctl_parser_types.ast_node_name decl_an)
| Some (Ctl_parser_types.Decl _ as decl_an) ->
| [Ctl_parser_types.Decl _ as decl_an] ->
"The reference " ^ (Ctl_parser_types.ast_node_name decl_an)
| _ -> failwith("decl_ref_or_selector_name must be called with a DeclRefExpr \
or an ObjCMessageExpr, but got " ^ (tag_name_of_node an))
@ -62,7 +62,7 @@ let iphoneos_target_sdk_version _ =
let available_ios_sdk an =
let open Ctl_parser_types in
match CTL.next_state_via_transition an (Some CTL.PointerToDecl) with
| Some Decl decl ->
| [Decl decl] ->
(match CPredicates.get_available_attr_ios_sdk (Decl decl) with
| Some version -> version
| None -> "")

@ -393,3 +393,19 @@ let within_responds_to_selector_block (cxt:CLintersContext.context) an =
List.mem ~equal:String.equal in_selector_block named_decl_info.ni_name
| None -> false)
| _ -> false
let objc_method_has_nth_parameter_of_type an _num _typ =
let open Clang_ast_t in
let num = match _num with
| ALVar.Const n -> (try
int_of_string n
with Failure _ -> -1)
| _ -> -1 in
match num, an, _typ with
| -1, _, _ -> false
| _, Ctl_parser_types.Decl (ObjCMethodDecl (_, _, omdi)), ALVar.Const typ ->
(match List.nth omdi.omdi_parameters num with
| Some (ParmVarDecl (_, _, qt, _)) ->
type_ptr_equal_type qt.qt_type_ptr typ
| _ -> false)
| _, _, _ -> false

@ -74,4 +74,8 @@ val method_return_type : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val get_available_attr_ios_sdk : Ctl_parser_types.ast_node -> string option
val within_responds_to_selector_block : CLintersContext.context -> Ctl_parser_types.ast_node -> bool
val within_responds_to_selector_block :
CLintersContext.context -> Ctl_parser_types.ast_node -> bool
val objc_method_has_nth_parameter_of_type :
Ctl_parser_types.ast_node -> ALVar.alexp -> ALVar.alexp -> bool

@ -20,6 +20,7 @@ type transitions =
| Body (** decl to stmt *)
| InitExpr (** decl to stmt *)
| Super (** decl to decl *)
| Parameters (** decl to decl *)
| Cond
| PointerToDecl (** stmt to decl *)
@ -96,6 +97,7 @@ module Debug = struct
| Body -> Format.pp_print_string fmt "Body"
| InitExpr -> Format.pp_print_string fmt "InitExpr"
| Super -> Format.pp_print_string fmt "Super"
| Parameters -> Format.pp_print_string fmt "Parameters"
| Cond -> Format.pp_print_string fmt "Cond"
| PointerToDecl -> Format.pp_print_string fmt "PointerToDecl" in
match trans_opt with
@ -537,25 +539,25 @@ let transition_decl_to_stmt d trs =
| Some InitExpr, EnumConstantDecl (_, _, _, ecdi) -> ecdi.ecdi_init_expr
| _, _ -> None in
match temp_res with
| Some st -> Some (Stmt st)
| _ -> None
| Some st -> [Stmt st]
| _ -> []
let transition_decl_to_decl_via_super d =
let decl_opt_to_ast_node_opt d_opt =
match d_opt with
| Some d' -> Some (Decl d')
| None -> None in
| Some d' -> [Decl d']
| None -> [] in
let do_ObjCImplementationDecl d =
match CAst_utils.get_impl_decl_info d with
| Some idi ->
decl_opt_to_ast_node_opt (CAst_utils.get_super_ObjCImplementationDecl idi)
| None -> None in
| None -> [] in
match d with
| Clang_ast_t.ObjCImplementationDecl _ ->
do_ObjCImplementationDecl d
| Clang_ast_t.ObjCInterfaceDecl (_, _, _, _, idi) ->
decl_opt_to_ast_node_opt (CAst_utils.get_decl_opt_with_decl_ref idi.otdi_super)
| _ -> None
| _ -> []
let transition_stmt_to_stmt_via_condition st =
let open Clang_ast_t in
@ -563,32 +565,40 @@ let transition_stmt_to_stmt_via_condition st =
| IfStmt (_, _ :: _ :: cond :: _)
| ConditionalOperator (_, cond:: _, _)
| ForStmt (_, [_; _; cond; _; _])
| WhileStmt (_, [_; cond; _]) -> Some (Stmt cond)
| _ -> None
| WhileStmt (_, [_; cond; _]) -> [Stmt cond]
| _ -> []
let transition_stmt_to_decl_via_pointer stmt =
let open Clang_ast_t in
match stmt with
| ObjCMessageExpr (_, _, _, obj_c_message_expr_info) ->
(match CAst_utils.get_decl_opt obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer with
| Some decl -> Some (Decl decl)
| None -> None)
| Some decl -> [Decl decl]
| None -> [])
| DeclRefExpr (_, _, _, decl_ref_expr_info) ->
(match CAst_utils.get_decl_opt_with_decl_ref decl_ref_expr_info.Clang_ast_t.drti_decl_ref with
| Some decl -> Some (Decl decl)
| None -> None)
| _ -> None
| Some decl -> [Decl decl]
| None -> [])
| _ -> []
let transition_decl_to_decl_via_parameters dec =
let open Clang_ast_t in
match dec with
| ObjCMethodDecl (_, _, omdi) ->
List.map ~f:(fun d -> Decl d) omdi.omdi_parameters
| _ -> []
(* 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 Parameters -> transition_decl_to_decl_via_parameters 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
| Stmt st, Some PointerToDecl ->
transition_stmt_to_decl_via_pointer st
| _, _ -> None
| _, _ -> []
(* Evaluation of formulas *)
@ -628,6 +638,8 @@ let rec eval_Atomic _pred_name args an lcxt =
| "method_return_type", [typ], an -> CPredicates.method_return_type an typ
| "within_responds_to_selector_block", [], an ->
CPredicates.within_responds_to_selector_block lcxt an
| "objc_method_has_nth_parameter_of_type", [num; typ], an ->
CPredicates.objc_method_has_nth_parameter_of_type an num typ
| _ -> failwith
("ERROR: Undefined Predicate or wrong set of arguments: '"
^ pred_name ^ "'")
@ -651,9 +663,9 @@ and eval_EF phi an lcxt trans =
(* Evaluate phi on node an' such that an -l-> an'. False if an' does not exists *)
and evaluate_on_transition phi an lcxt l =
match next_state_via_transition an l with
| Some succ -> eval_formula phi succ lcxt
| None -> false
let succs = next_state_via_transition an l in
List.exists ~f:(fun an' -> eval_formula phi an' lcxt) succs
(* an, lcxt |= EX phi <=> exists an' in Successors(st): an', lcxt |= phi

@ -20,6 +20,7 @@ type transitions =
| Body (* decl to stmt *)
| InitExpr (* decl to stmt *)
| Super (* decl to decl *)
| Parameters (* decl to decl *)
| Cond
| PointerToDecl (* stmt to decl *)
@ -97,7 +98,7 @@ val eval_formula : t -> ast_node -> CLintersContext.context -> bool
val save_dotty_when_in_debug_mode : SourceFile.t -> unit
val next_state_via_transition : ast_node -> transitions option -> ast_node option
val next_state_via_transition : ast_node -> transitions option -> ast_node list
val create_ctl_evaluation_tracker : SourceFile.t -> unit

@ -192,6 +192,7 @@ transition_label:
| "Body" | "body" -> Some CTL.Body
| "InitExpr" | "initexpr" -> Some CTL.InitExpr
| "Cond" | "cond" -> Some CTL.Cond
| "Parameters" | "parameters" -> Some CTL.Parameters
| "PointerToDecl" | "pointertodecl" -> Some CTL.PointerToDecl
| _ -> None }
;

@ -47,6 +47,9 @@ codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m23, 99, TEST_B
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m24, 100, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m25, 101, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m26, 102, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m26:pname2:pname3:pname4:, 103, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m26:pname2:pname3:pname4:, 103, TEST_NTH_PARAM_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m26:pname2:pname3:pname4:, 103, TEST_PARAM_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m3, 75, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m4, 76, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m7, 79, TEST_BUILTIN_TYPE, []

@ -5,7 +5,17 @@ GLOBAL-MACROS {
LET global_is_subclass_of(x) =
is_class(x) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl;
};
LET parameter_of_type(x) =
WHEN
has_type(x)
HOLDS-IN-NODE ParmVarDecl;
LET method_has_a_parameter_with_type(x) =
WHEN
HOLDS-NEXT WITH-TRANSITION Parameters
(has_type(x))
HOLDS-IN-NODE ObjCMethodDecl;
};
//Check that class A is not subclassed.
@ -153,3 +163,23 @@ DEFINE-CHECKER TEST_VAR_TYPE_CHECK = {
SET message = "Var has type int or long";
};
DEFINE-CHECKER TEST_PARAM_TYPE_CHECK = {
SET report_when =
method_has_a_parameter_with_type("REGEXP('This.+')*" );
SET message = "Found a method with a parameter of type....";
};
DEFINE-CHECKER TEST_NTH_PARAM_TYPE_CHECK = {
SET report_when =
WHEN
objc_method_has_nth_parameter_of_type("2", "REGEXP('This.+')*")
HOLDS-IN-NODE ObjCMethodDecl;
SET message = "Found a method with nth parameter of type....";
};

@ -100,4 +100,8 @@
- (unsigned int**)m24;
- (A*)m25;
- (ThisIsAVeryLongName*)m26;
- (void)m26:(int)p1
pname2:(float)p2
pname3:(ThisIsAVeryLongName*)p3
pname4:(A*)p4;
@end

Loading…
Cancel
Save