[frontend] Add translation of dictionaryWithObjects:forKeys:count:

Summary:
This diff adds translation of `dictionaryWithObjects:forKeys:count:`. In the previous implementation it was
translated as if it was `dictionaryWtihObjectsAndKeys:`, but their function parameters are different.

In this diff, it translates an array literal `NSDictionary* a = @ [ @"firstName": @"Foo", @"lastName":@"Bar" ];` to

```
n$1=NSString.stringWithUTF8:(@"firstName")
n$2=NSNumber.stringWithUTF8:(@"Foo")
n$3=NSNumber.stringWithUTF8:(@"lastName")
n$4=NSNumber.stringWithUTF8:(@"Bar")
temp1[0]:objc_object*=n$1
temp1[1]:objc_object*=n$3
temp2[0]:objc_object*=n$2
temp2[1]:objc_object*=n$4
n$3=NSDictionary.dictionaryWithObjects:forKeys:count:(temp2:objc_object* const [2*8], temp1:objc_object*const [2*8], 2:int)
```

where `temp` is an additional local variable declared as array.

See,
https://developer.apple.com/documentation/foundation/nsdictionary/1574184-dictionarywithobjects?language=objc

https://developer.apple.com/documentation/foundation/nsdictionary/1574181-dictionarywithobjectsandkeys

{F316854542}

Reviewed By: skcho

Differential Revision: D23447042

fbshipit-source-id: 14b7c3f2b
master
Qianyi Shu 4 years ago committed by Facebook GitHub Bot
parent 20a8890fd5
commit 5ed04a8e9a

@ -24,6 +24,8 @@ let alloc = "alloc"
let arrayWithObjects_count = "arrayWithObjects:count:"
let dictionaryWithObjects_forKeys_count = "dictionaryWithObjects:forKeys:count:"
let dealloc = "dealloc"
let assert_fail = "__assert_fail"

@ -24,6 +24,8 @@ val alloc : string
val arrayWithObjects_count : string
val dictionaryWithObjects_forKeys_count : string
val dealloc : string
val assert_fail : string

@ -668,6 +668,16 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
None )
let get_dictionaryWithObjects_forKeys_count_infos method_pointer =
Option.bind (CAst_utils.get_decl_opt method_pointer) ~f:(function
| Clang_ast_t.ObjCMethodDecl
(decl_info, {ni_name}, {omdi_parameters= ParmVarDecl (_, _, objects_qual_typ, _) :: _})
when String.equal ni_name CFrontend_config.dictionaryWithObjects_forKeys_count ->
Some (decl_info, objects_qual_typ)
| _ ->
None )
let this_expr_trans stmt_info ?class_qual_type trans_state sil_loc =
let this_pvar, this_typ = get_this_pvar_typ stmt_info ?class_qual_type trans_state.context in
let return = (Exp.Lvar this_pvar, this_typ) in
@ -2955,9 +2965,122 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
and objCDictionaryLiteral_trans trans_state expr_info stmt_info stmts dict_literal_info =
let method_pointer = dict_literal_info.Clang_ast_t.odlei_dict_method in
let stmts = CGeneral_utils.swap_elements_list stmts in
let stmts = stmts @ [Ast_expressions.create_nil stmt_info] in
objCArrayDictLiteral_trans trans_state expr_info stmt_info stmts method_pointer
match get_dictionaryWithObjects_forKeys_count_infos method_pointer with
| Some infos ->
objCDictLiteral_dictionaryWithObjects_forKeys_count_trans trans_state expr_info stmt_info
stmts infos method_pointer
| None ->
let stmts = CGeneral_utils.swap_elements_list stmts in
let stmts = stmts @ [Ast_expressions.create_nil stmt_info] in
objCArrayDictLiteral_trans trans_state expr_info stmt_info stmts method_pointer
(** Translates an dictionary literal @ [ @"firstName": @"Foo", @"lastName":@"Bar" ] to
{[
n$1=NSString.stringWithUTF8:(@"firstName")
n$2=NSNumber.stringWithUTF8:(@"Foo")
n$3=NSNumber.stringWithUTF8:(@"lastName")
n$4=NSNumber.stringWithUTF8:(@"Bar")
temp1[0]:objc_object*=n$1
temp1[1]:objc_object*=n$3
temp2[0]:objc_object*=n$2
temp2[1]:objc_object*=n$4
n$3=NSDictionary.dictionaryWithObjects:forKeys:count:(temp2:objc_object* const [2*8],
temp1:objc_object* const [2*8], 2:int)
]}
where [temp1] [temp2] are additional local variables declared as array. *)
and objCDictLiteral_dictionaryWithObjects_forKeys_count_trans
({context= {procdesc; tenv; translation_unit_context} as context} as trans_state) expr_info
stmt_info stmts (decl_info, objects_qual_typ) method_pointer =
let loc = CLocation.location_of_stmt_info translation_unit_context.source_file stmt_info in
(* 1. Add a temporary local variable for an array *)
let temp1 =
CVar_decl.mk_temp_sil_var procdesc ~name:"SIL_dictionaryWithObjects_forKeys_count1___"
in
let temp2 =
CVar_decl.mk_temp_sil_var procdesc ~name:"SIL_dictionaryWithObjects_forKeys_count2___"
in
let length = List.length stmts |> IntLit.of_int in
let create_var = function
| temp ->
let array_typ =
match CType_decl.qual_type_to_sil_type tenv objects_qual_typ with
| Typ.{desc= Tptr (t, _)} ->
Typ.mk_array ~length ~stride:(IntLit.of_int 8) t
| _ ->
Typ.void_star
in
(Exp.Lvar temp, array_typ)
in
let append_var temp array_typ =
Procdesc.append_locals procdesc
[ { ProcAttributes.name= Pvar.get_name temp
; typ= array_typ
; modify_in_block= false
; is_constexpr= false
; is_declared_unused= false } ]
in
let ((temp1_var, array1_typ) as temp1_with_typ) = create_var temp1 in
let ((temp2_var, array2_typ) as temp2_with_typ) = create_var temp2 in
append_var temp1 array1_typ ;
append_var temp2 array2_typ ;
(* 2. Translate array elements *)
let res_trans_elems = List.mapi ~f:(exec_instruction_with_trans_state trans_state None) stmts in
(* 3. Add array initialization (elements assignments) *)
let none_id = Ident.create_none () in
let array_init temp_var temp_with_typ idx_mod =
let instrs =
List.mapi res_trans_elems ~f:(fun i {return= e, typ} ->
if Int.equal (i % 2) idx_mod then
let idx = Exp.Const (Cint (IntLit.of_int (i / 2))) in
[ Sil.Load {id= none_id; e; root_typ= typ; typ; loc}
; Sil.Store {e1= Lindex (temp_var, idx); root_typ= typ; typ; e2= e; loc} ]
else [] )
|> List.concat
in
mk_trans_result temp_with_typ {empty_control with instrs}
in
let res_trans_array1 = array_init temp1_var temp1_with_typ 1 in
let res_trans_array2 = array_init temp2_var temp2_with_typ 0 in
(* 4. Add a function call. *)
let res_trans_call =
let method_type_no_ref = CType_decl.get_type_from_expr_info expr_info tenv in
let method_type = add_reference_if_glvalue method_type_no_ref expr_info in
let actuals =
[ temp1_with_typ
; temp2_with_typ
; (Exp.Const (Cint (IntLit.div length (IntLit.of_int 2))), Typ.int) ]
in
let callee_name, method_call_type =
let typ =
CAst_utils.qual_type_of_decl_ptr
(Option.value_exn decl_info.Clang_ast_t.di_parent_pointer)
in
let obj_c_message_expr_info =
{ Clang_ast_t.omei_selector= CFrontend_config.dictionaryWithObjects_forKeys_count
; omei_receiver_kind= `Class typ
; omei_is_definition_found= true
; omei_decl_pointer= method_pointer }
in
let callee_ms_opt =
Option.bind method_pointer ~f:(fun method_pointer ->
CMethod_trans.method_signature_of_pointer tenv method_pointer )
in
get_callee_objc_method context obj_c_message_expr_info callee_ms_opt actuals
in
let method_sil = Exp.Const (Cfun callee_name) in
let call_flags =
{ CallFlags.default with
cf_virtual= CMethod_trans.equal_method_call_type method_call_type CMethod_trans.MCVirtual
}
in
create_call_instr trans_state method_type method_sil actuals loc call_flags
~is_objc_method:true ~is_inherited_ctor:false
in
collect_trans_results procdesc ~return:res_trans_call.return
(res_trans_elems @ [res_trans_array1; res_trans_array2; res_trans_call])
and objCStringLiteral_trans trans_state stmt_info stmts info =

@ -11,14 +11,14 @@ digraph cfg {
"get_array1.5988b7ad8acf5c81cef9a72d072073c1_3" -> "get_array1.5988b7ad8acf5c81cef9a72d072073c1_2" ;
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_1" [label="1: Start get_array2\nFormals: \nLocals: \n " color=yellow style=filled]
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_1" [label="1: Start get_array2\nFormals: \nLocals: 0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0:objc_object* const [6*8] 0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1:objc_object* const [6*8] \n " color=yellow style=filled]
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_1" -> "get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_3" ;
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_2" [label="2: Exit get_array2 \n " color=yellow style=filled]
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_3" [label="3: Return Stmt \n n$5=_fun_NSString.stringWithUTF8String:(\"Matt\":char* const ) [line 23, column 27]\n n$0=_fun_NSString.stringWithUTF8String:(\"firstName\":char* const ) [line 23, column 12]\n n$1=_fun_NSString.stringWithUTF8String:(\"Galloway\":char* const ) [line 23, column 50]\n n$2=_fun_NSString.stringWithUTF8String:(\"lastName\":char* const ) [line 23, column 36]\n n$3=_fun_NSNumber.numberWithInt:(28:int) [line 23, column 72]\n n$4=_fun_NSString.stringWithUTF8String:(\"age\":char* const ) [line 23, column 63]\n n$6=_fun_NSDictionary.dictionaryWithObjects:forKeys:count:(n$5:objc_object*,n$0:objc_object*,n$1:objc_object*,n$2:objc_object*,n$3:objc_object*,n$4:objc_object*,null:objc_object*) [line 23, column 10]\n *&return:NSDictionary*=n$6 [line 23, column 3]\n " shape="box"]
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_3" [label="3: Return Stmt \n n$2=_fun_NSString.stringWithUTF8String:(\"firstName\":char* const ) [line 23, column 12]\n n$3=_fun_NSString.stringWithUTF8String:(\"Matt\":char* const ) [line 23, column 27]\n n$4=_fun_NSString.stringWithUTF8String:(\"lastName\":char* const ) [line 23, column 36]\n n$5=_fun_NSString.stringWithUTF8String:(\"Galloway\":char* const ) [line 23, column 50]\n n$6=_fun_NSString.stringWithUTF8String:(\"age\":char* const ) [line 23, column 63]\n n$7=_fun_NSNumber.numberWithInt:(28:int) [line 23, column 72]\n _=*n$3:objc_object* [line 23, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0[0]:objc_object*=n$3 [line 23, column 10]\n _=*n$5:objc_object* [line 23, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0[1]:objc_object*=n$5 [line 23, column 10]\n _=*n$7:objc_object* [line 23, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0[2]:objc_object*=n$7 [line 23, column 10]\n _=*n$2:objc_object* [line 23, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1[0]:objc_object*=n$2 [line 23, column 10]\n _=*n$4:objc_object* [line 23, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1[1]:objc_object*=n$4 [line 23, column 10]\n _=*n$6:objc_object* [line 23, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1[2]:objc_object*=n$6 [line 23, column 10]\n n$9=_fun_NSDictionary.dictionaryWithObjects:forKeys:count:(&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0:objc_object* const [6*8],&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1:objc_object* const [6*8],3:int) [line 23, column 10]\n *&return:NSDictionary*=n$9 [line 23, column 3]\n " shape="box"]
"get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_3" -> "get_array2.84aa3c70cb20e7edbe4f0b8d0bd6aa3d_2" ;

@ -100,7 +100,7 @@ void nsdictionary_enumerator_linear(NSDictionary* dict) {
}
}
void nsdictionary_enumerate_call_constant_FP() {
void nsdictionary_enumerate_call_constant() {
NSDictionary* dict =
@{@"helloString" : @"Hello, World!",
@"magicNumber" : @42};

@ -28,13 +28,13 @@ codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear2, 6
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_constant, 13, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_with_objects_linear, 14 + 15 ⋅ n_entries + 3 ⋅ n_entries + 2 ⋅ (1+max(0, n_entries)) + 4 ⋅ (1+max(0, n_entries)), OnUIThread:false, [{1+max(0, n_entries)},Loop,{1+max(0, n_entries)},Loop,{n_entries},Loop,{n_entries},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_call_constant_FP, , OnUIThread:false, [Unbounded value dict->elements.length.ub,Call to nsdictionary_all_values_linear,Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 52, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_call_constant, 65, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 69, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerator_linear, 5 + dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_fast_enumerate_linear, 5 + dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_find_key_constant, 19, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_dictionary_constant, 3, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_literal_constant, 41, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_literal_constant, 45, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_with_dictionary_linear_FP, , OnUIThread:false, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSInteger.m, nsinteger_value_linear, 3 + 3 ⋅ integer + 2 ⋅ (1+max(0, integer)), OnUIThread:false, [{1+max(0, integer)},Loop,{integer},Loop]
codetoanalyze/objc/performance/NSInteger.m, nsnumber_number_with_int_integer_value_constant, 34, OnUIThread:false, []

@ -1,7 +1,5 @@
codetoanalyze/objc/performance/NSArray.m, nsarray_empty_array_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSArray.m, nsarray_init_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_call_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded value dict->elements.length.ub,Call to nsdictionary_all_values_linear,Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_call_constant_FP, 5, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [Unknown value from: NSDictionary.dictionaryWithObjects:forKeys:count:,Call,<LHS trace>,Parameter `dict->elements[*]`,Binary operation: ([0, +oo] + 1):signed32 by call to `nsdictionary_all_values_linear` ]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_with_dictionary_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_with_dictionary_linear_FP, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [<LHS trace>,Unknown value from: NSDictionary.initWithDictionary:,Binary operation: ([0, +oo] + 1):signed32]
codetoanalyze/objc/performance/NSMutableArray.m, nsarray_new_constant, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]

@ -1,21 +1,21 @@
/* @generated */
digraph cfg {
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_1" [label="1: Start npe_property_nullable\nFormals: \nLocals: child:Person* person:Person* \n " color=yellow style=filled]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_1" [label="1: Start npe_property_nullable\nFormals: \nLocals: 0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0:objc_object* const [2*8] 0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1:objc_object* const [2*8] child:Person* person:Person* \n " color=yellow style=filled]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_1" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" ;
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_2" [label="2: Exit npe_property_nullable \n " color=yellow style=filled]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" [label="3: Return Stmt \n n$1=*&child:Person* [line 56, column 21]\n n$0=_fun_NSString.stringWithUTF8String:(\"key\":char* const ) [line 56, column 12]\n n$2=_fun_NSDictionary.dictionaryWithObjects:forKeys:count:(n$1:objc_object*,n$0:objc_object*,null:objc_object*) [line 56, column 10]\n *&return:NSDictionary*=n$2 [line 56, column 3]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" [label="3: Return Stmt \n n$2=_fun_NSString.stringWithUTF8String:(\"key\":char* const ) [line 56, column 12]\n n$3=*&child:Person* [line 56, column 21]\n _=*n$3:objc_object* [line 56, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0[0]:objc_object*=n$3 [line 56, column 10]\n _=*n$2:objc_object* [line 56, column 10]\n *&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1[0]:objc_object*=n$2 [line 56, column 10]\n n$5=_fun_NSDictionary.dictionaryWithObjects:forKeys:count:(&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count1___n$0:objc_object* const [2*8],&0$?%__sil_tmpSIL_dictionaryWithObjects_forKeys_count2___n$1:objc_object* const [2*8],1:int) [line 56, column 10]\n *&return:NSDictionary*=n$5 [line 56, column 3]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_2" ;
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" [label="4: DeclStmt \n VARIABLE_DECLARED(child:Person*); [line 55, column 3]\n n$3=*&person:Person* [line 55, column 19]\n n$4=_fun_Person.child(n$3:Person*) [line 55, column 26]\n *&child:Person*=n$4 [line 55, column 3]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" [label="4: DeclStmt \n VARIABLE_DECLARED(child:Person*); [line 55, column 3]\n n$6=*&person:Person* [line 55, column 19]\n n$7=_fun_Person.child(n$6:Person*) [line 55, column 26]\n *&child:Person*=n$7 [line 55, column 3]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" ;
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" [label="5: DeclStmt \n VARIABLE_DECLARED(person:Person*); [line 54, column 3]\n n$5=_fun___objc_alloc_no_fail(sizeof(t=Person):unsigned long) [line 54, column 20]\n n$6=_fun_NSObject.init(n$5:Person*) virtual [line 54, column 20]\n *&person:Person*=n$6 [line 54, column 3]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" [label="5: DeclStmt \n VARIABLE_DECLARED(person:Person*); [line 54, column 3]\n n$8=_fun___objc_alloc_no_fail(sizeof(t=Person):unsigned long) [line 54, column 20]\n n$9=_fun_NSObject.init(n$8:Person*) virtual [line 54, column 20]\n *&person:Person*=n$9 [line 54, column 3]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" ;

Loading…
Cancel
Save