[frontend] Add translation of arrayWithObjects:count:

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

In this diff, it translates an array literal `NSArray* a = @ [ 2, 3 ];` to

```
n$1=NSNumber.numberWithInt:(2:int)
n$2=NSNumber.numberWithInt:(3:int)
temp[0]:objc_object*=n$1
temp[1]:objc_object*=n$2
n$3=NSArray.arrayWithObjects:count:(temp:objc_object* const [2*8],2:int)
a:NSArray*=n$3
```

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

See,
https://developer.apple.com/documentation/foundation/nsarray/1460145-arraywithobjects
https://developer.apple.com/documentation/foundation/nsarray/1460096-arraywithobjects?language=objc

Reviewed By: jvillard

Differential Revision: D22631305

fbshipit-source-id: 5be0a55d4
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent 9690dba871
commit 928137fb34

@ -22,6 +22,8 @@ type decl_trans_context = [`DeclTraversal | `Translation]
let alloc = "alloc"
let arrayWithObjects_count = "arrayWithObjects:count:"
let dealloc = "dealloc"
let assert_fail = "__assert_fail"

@ -22,6 +22,8 @@ type decl_trans_context = [`DeclTraversal | `Translation]
val alloc : string
val arrayWithObjects_count : string
val dealloc : string
val assert_fail : string

@ -653,6 +653,16 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(pvar, CType_decl.qual_type_to_sil_type tenv class_qual_type)
let get_arrayWithObjects_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.arrayWithObjects_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
@ -2781,8 +2791,91 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
and objCArrayLiteral_trans trans_state expr_info stmt_info stmts array_literal_info =
let method_pointer = array_literal_info.Clang_ast_t.oalei_array_method in
let stmts = stmts @ [Ast_expressions.create_nil stmt_info] in
objCArrayDictLiteral_trans trans_state expr_info stmt_info stmts method_pointer
match get_arrayWithObjects_count_infos method_pointer with
| Some infos ->
objCArrayLiteral_arrayWithObjects_count_trans trans_state expr_info stmt_info stmts infos
method_pointer
| None ->
let stmts = stmts @ [Ast_expressions.create_nil stmt_info] in
objCArrayDictLiteral_trans trans_state expr_info stmt_info stmts method_pointer
(** Translates an array literal `NSArray* a = @ [ @2, @3 ];` to
n$1=NSNumber.numberWithInt:(2:int)
n$2=NSNumber.numberWithInt:(3:int)
temp[0]:objc_object*=n$1
temp[1]:objc_object*=n$2
n$3=NSArray.arrayWithObjects:count:(temp:objc_object* const [2*8],2:int)
a:NSArray*=n$3
where `temp` is an additional local variable declared as array. *)
and objCArrayLiteral_arrayWithObjects_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 temp = CVar_decl.mk_temp_sil_var procdesc ~name:"SIL_arrayWithObjects_count___" in
let length = List.length stmts |> IntLit.of_int in
let ((temp_var, array_typ) as temp_with_typ) =
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
Procdesc.append_locals procdesc
[ { ProcAttributes.name= Pvar.get_name temp
; typ= array_typ
; modify_in_block= false
; is_constexpr= false } ] ;
(* 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 res_trans_array =
let instrs =
List.mapi res_trans_elems ~f:(fun i {return= e, typ} ->
let idx = Exp.Const (Cint (IntLit.of_int i)) in
Sil.Store {e1= Lindex (temp_var, idx); root_typ= typ; typ; e2= e; loc} )
in
mk_trans_result temp_with_typ {empty_control with instrs}
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 = [temp_with_typ; (Exp.Const (Cint length), 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.arrayWithObjects_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_array; res_trans_call])
and objCDictionaryLiteral_trans trans_state expr_info stmt_info stmts dict_literal_info =

@ -58,11 +58,6 @@ codetoanalyze/objc/biabduction/npe/UpdateDict.m, nullable_NSDictionary_objectFor
codetoanalyze/objc/biabduction/npe/UpdateDict.m, nullable_NSMapTable_objectForKey, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure nullable_NSMapTable_objectForKey(),Taking true branch,Taking true branch]
codetoanalyze/objc/biabduction/npe/UpdateDict.m, update_array_with_null, 5, NULL_DEREFERENCE, B1, ERROR, [start of procedure update_array_with_null()]
codetoanalyze/objc/biabduction/npe/UpdateDict.m, update_dict_with_key_null, 10, NULL_DEREFERENCE, B1, ERROR, [start of procedure update_dict_with_key_null(),Skipping dictionaryWithObjectsAndKeys:: method has no implementation]
codetoanalyze/objc/biabduction/npe/nil_in_array_literal.m, Arr.insertNilBad, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure insertNilBad,start of procedure initA,Taking true branch,return from a call to A.initA]
codetoanalyze/objc/biabduction/npe/nil_in_array_literal.m, Arr.nilInArrayLiteral0, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInArrayLiteral0]
codetoanalyze/objc/biabduction/npe/nil_in_array_literal.m, Arr.nilInArrayLiteral1, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInArrayLiteral1]
codetoanalyze/objc/biabduction/npe/nil_in_array_literal.m, Arr.nilInArrayLiteral2, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInArrayLiteral2]
codetoanalyze/objc/biabduction/npe/nil_in_array_literal.m, Arr.nilInArrayLiteral3, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInArrayLiteral3]
codetoanalyze/objc/biabduction/npe/nil_in_array_literal.m, Arr.nilInArrayWithObject, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInArrayWithObject]
codetoanalyze/objc/biabduction/npe/nil_in_dictionary_literal.m, ADict.nilInDictionaryLiteralKey0, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInDictionaryLiteralKey0]
codetoanalyze/objc/biabduction/npe/nil_in_dictionary_literal.m, ADict.nilInDictionaryLiteralKey1, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure nilInDictionaryLiteralKey1]

@ -38,28 +38,28 @@ bool myrand(void);
return;
}
- (void)nilInArrayLiteral0 {
- (void)nilInArrayLiteral0_FN {
NSString* str = nil;
// nil argument in array literal crashes
NSArray* foo = @[ str ];
}
- (void)nilInArrayLiteral1 {
- (void)nilInArrayLiteral1_FN {
NSString* str = nil;
// nil argument in array literal crashes
NSArray* foo = @[ str, @"bbb" ];
}
- (void)nilInArrayLiteral2 {
- (void)nilInArrayLiteral2_FN {
NSString* str = nil;
// nil argument in array literal crashes
NSArray* foo = @[ @"aaa", str, @"bbb" ];
}
- (void)nilInArrayLiteral3 {
- (void)nilInArrayLiteral3_FN {
NSString* str = nil;
// nil argument in array literal crashes
@ -75,7 +75,7 @@ bool myrand(void);
return foo;
}
- (NSMutableArray*)insertNilBad {
- (NSMutableArray*)insertNilBad_FN {
NSMutableArray* ar = [NSMutableArray new];
A* a = [A initA];
[ar addObject:@[ a ]];
@ -87,7 +87,7 @@ bool myrand(void);
int ArrMain() {
Arr* a = [Arr alloc];
[a noProblem];
[a nilInArrayLiteral0];
[a nilInArrayLiteral0_FN];
[a nilInArrayWithObject];
return 0;
}

@ -1,6 +1,6 @@
/* @generated */
digraph cfg {
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: item:NSString* germanCars:NSArray* s:NSString* \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: item:NSString* germanCars:NSArray* 0$?%__sil_tmpSIL_arrayWithObjects_count___n$11:objc_object* const [6*8] s:NSString* \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_12" ;
@ -44,7 +44,7 @@ digraph cfg {
"main.fad58de7366495db4650cfefac2fcd61_11" -> "main.fad58de7366495db4650cfefac2fcd61_10" ;
"main.fad58de7366495db4650cfefac2fcd61_12" [label="12: DeclStmt \n VARIABLE_DECLARED(germanCars:NSArray*); [line 14, column 3]\n n$16=_fun_NSString.stringWithUTF8String:(\"Mercedes-Benz\":char* const ) [line 15, column 5]\n n$11=_fun_NSString.stringWithUTF8String:(\"BMW\":char* const ) [line 16, column 5]\n n$12=_fun_NSString.stringWithUTF8String:(\"Porsche\":char* const ) [line 17, column 5]\n n$13=_fun_NSString.stringWithUTF8String:(\"Opel\":char* const ) [line 18, column 5]\n n$14=_fun_NSString.stringWithUTF8String:(\"Volkswagen\":char* const ) [line 19, column 5]\n n$15=_fun_NSString.stringWithUTF8String:(\"Audi\":char* const ) [line 20, column 5]\n n$17=_fun_NSArray.arrayWithObjects:count:(n$16:objc_object*,n$11:objc_object*,n$12:objc_object*,n$13:objc_object*,n$14:objc_object*,n$15:objc_object*,null:objc_object*) [line 14, column 25]\n *&germanCars:NSArray*=n$17 [line 14, column 3]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_12" [label="12: DeclStmt \n VARIABLE_DECLARED(germanCars:NSArray*); [line 14, column 3]\n n$12=_fun_NSString.stringWithUTF8String:(\"Mercedes-Benz\":char* const ) [line 15, column 5]\n n$13=_fun_NSString.stringWithUTF8String:(\"BMW\":char* const ) [line 16, column 5]\n n$14=_fun_NSString.stringWithUTF8String:(\"Porsche\":char* const ) [line 17, column 5]\n n$15=_fun_NSString.stringWithUTF8String:(\"Opel\":char* const ) [line 18, column 5]\n n$16=_fun_NSString.stringWithUTF8String:(\"Volkswagen\":char* const ) [line 19, column 5]\n n$17=_fun_NSString.stringWithUTF8String:(\"Audi\":char* const ) [line 20, column 5]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11[0]:objc_object*=n$12 [line 14, column 25]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11[1]:objc_object*=n$13 [line 14, column 25]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11[2]:objc_object*=n$14 [line 14, column 25]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11[3]:objc_object*=n$15 [line 14, column 25]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11[4]:objc_object*=n$16 [line 14, column 25]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11[5]:objc_object*=n$17 [line 14, column 25]\n n$18=_fun_NSArray.arrayWithObjects:count:(&0$?%__sil_tmpSIL_arrayWithObjects_count___n$11:objc_object* const [6*8],6:int) [line 14, column 25]\n *&germanCars:NSArray*=n$18 [line 14, column 3]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_12" -> "main.fad58de7366495db4650cfefac2fcd61_11" ;

@ -1,17 +1,17 @@
/* @generated */
digraph cfg {
"get_array.bca6b16c85e5b8ba530f380271b2ec79_1" [label="1: Start get_array\nFormals: \nLocals: animals:NSArray* \n " color=yellow style=filled]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_1" [label="1: Start get_array\nFormals: \nLocals: 0$?%__sil_tmpSIL_arrayWithObjects_count___n$0:objc_object* const [2*8] animals:NSArray* \n " color=yellow style=filled]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_1" -> "get_array.bca6b16c85e5b8ba530f380271b2ec79_4" ;
"get_array.bca6b16c85e5b8ba530f380271b2ec79_2" [label="2: Exit get_array \n " color=yellow style=filled]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_3" [label="3: Return Stmt \n n$1=_fun_NSString.stringWithUTF8String:(\"cat\":char* const ) [line 12, column 13]\n n$0=_fun_NSString.stringWithUTF8String:(\"dog\":char* const ) [line 12, column 21]\n n$2=_fun_NSArray.arrayWithObjects:count:(n$1:objc_object*,n$0:objc_object*,null:objc_object*) [line 12, column 10]\n *&return:NSArray*=n$2 [line 12, column 3]\n " shape="box"]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_3" [label="3: Return Stmt \n n$1=_fun_NSString.stringWithUTF8String:(\"cat\":char* const ) [line 12, column 13]\n n$2=_fun_NSString.stringWithUTF8String:(\"dog\":char* const ) [line 12, column 21]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$0[0]:objc_object*=n$1 [line 12, column 10]\n *&0$?%__sil_tmpSIL_arrayWithObjects_count___n$0[1]:objc_object*=n$2 [line 12, column 10]\n n$3=_fun_NSArray.arrayWithObjects:count:(&0$?%__sil_tmpSIL_arrayWithObjects_count___n$0:objc_object* const [2*8],2:int) [line 12, column 10]\n *&return:NSArray*=n$3 [line 12, column 3]\n " shape="box"]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_3" -> "get_array.bca6b16c85e5b8ba530f380271b2ec79_2" ;
"get_array.bca6b16c85e5b8ba530f380271b2ec79_4" [label="4: DeclStmt \n VARIABLE_DECLARED(animals:NSArray*); [line 11, column 3]\n n$4=_fun_NSString.stringWithUTF8String:(\"cat\":char* const ) [line 11, column 48]\n n$3=_fun_NSString.stringWithUTF8String:(\"dog\":char* const ) [line 11, column 56]\n n$5=_fun_NSArray.arrayWithObjects:(n$4:objc_object*,n$3:NSString*,null:void*) [line 11, column 22]\n *&animals:NSArray*=n$5 [line 11, column 3]\n " shape="box"]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_4" [label="4: DeclStmt \n VARIABLE_DECLARED(animals:NSArray*); [line 11, column 3]\n n$5=_fun_NSString.stringWithUTF8String:(\"cat\":char* const ) [line 11, column 48]\n n$4=_fun_NSString.stringWithUTF8String:(\"dog\":char* const ) [line 11, column 56]\n n$6=_fun_NSArray.arrayWithObjects:(n$5:objc_object*,n$4:NSString*,null:void*) [line 11, column 22]\n *&animals:NSArray*=n$6 [line 11, column 3]\n " shape="box"]
"get_array.bca6b16c85e5b8ba530f380271b2ec79_4" -> "get_array.bca6b16c85e5b8ba530f380271b2ec79_3" ;

@ -1,4 +1,4 @@
codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 42, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 50, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array.length + 3 ⋅ (array.length + 1), OnUIThread:false, [{array.length + 1},Loop,{array.length},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_add_object_constant, 8, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear_FN, 8, OnUIThread:false, []
@ -20,8 +20,8 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear_FN, 14, OnUITh
codetoanalyze/objc/performance/NSArray.m, nsarray_last_object_constant, 4, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear_FN, 10, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant_FP, , OnUIThread:false, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 30, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn_FN, 9, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 34, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn_FN, 10, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 5, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear_FP, , OnUIThread:false, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear_FP, , OnUIThread:false, [Unbounded loop,Loop]

@ -8,10 +8,7 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear_FP, 0,
codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear_FP, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,Binary operation: ([0, +oo] + 1):signed32]
codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear_FN, 3, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [<LHS trace>,Assignment,<RHS trace>,Unknown value from: NSArray.nextObject,Assignment,Binary operation: ([-oo, +oo] + [-oo, +oo]):signed64]
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant_FP, 3, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: NSArray.arrayWithObjects:count:,Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]]
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant_FP, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,Binary operation: ([0, +oo] + 1):signed32]
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 4, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: NSSortDescriptor.initWithKey:ascending:,Assignment,Array access: Offset added: [-oo, +oo] Size: [0, +oo]]
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn_FN, 3, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: NSSortDescriptor.initWithKey:ascending:,Assignment,Array access: Offset added: [-oo, +oo] Size: [0, +oo]]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear_FP, 1, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,Binary operation: ([0, +oo] + 1):signed32]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]

Loading…
Cancel
Save