Treating blocks iterators for NSArray

master
Dino Distefano 10 years ago
parent 14c41278e6
commit 35b7011f81

@ -26,6 +26,10 @@ let dummy_stmt_info () =
Clang_ast_t.si_source_range = dummy_source_range ()
}
(* given a stmt_info return the same stmt_info with a fresh pointer *)
let fresh_stmt_info stmt_info =
{ stmt_info with Clang_ast_t.si_pointer = Ast_utils.get_fresh_pointer () }
let dummy_decl_info decl_info =
{
decl_info with
@ -48,6 +52,14 @@ let empty_decl_info = {
Clang_ast_t.di_full_comment = None;
}
let empty_var_decl_info = {
Clang_ast_t.vdi_storage_class = None;
Clang_ast_t.vdi_tls_kind =`Tls_none;
Clang_ast_t.vdi_is_module_private = false;
Clang_ast_t.vdi_is_nrvo_variable = false;
Clang_ast_t.vdi_init_expr = None;
}
let stmt_info_with_fresh_pointer stmt_info =
{
Clang_ast_t.si_pointer = Ast_utils.get_fresh_pointer ();
@ -71,6 +83,14 @@ let create_id_type () = create_qual_type "id"
let create_char_type () = create_qual_type "char *"
let create_BOOL_type () = { qt_raw = "BOOL"; qt_desugared = Some("signed char") }
let create_void_unsigned_long_type () = create_qual_type "void *(unsigned long)"
let create_unsigned_long_type () = create_qual_type "unsigned long"
let create_void_void_type () = create_qual_type "void (void *)"
let create_integer_literal stmt_info n =
let stmt_info = dummy_stmt_info () in
let expr_info = {
@ -132,11 +152,17 @@ let dummy_stmt () =
let make_stmt_info di =
{ Clang_ast_t.si_pointer = di.Clang_ast_t.di_pointer; Clang_ast_t.si_source_range = di.Clang_ast_t.di_source_range }
let make_expr_info_with_objc_kind qt objc_kind = {
let make_expr_info qt vk objc_kind = {
Clang_ast_t.ei_qual_type = qt;
Clang_ast_t.ei_value_kind = `LValue;
Clang_ast_t.ei_value_kind = vk;
Clang_ast_t.ei_object_kind = objc_kind;}
let make_expr_info_with_objc_kind qt objc_kind =
make_expr_info qt `LValue objc_kind
let make_lvalue_obc_prop_expr_info qt =
make_expr_info qt `LValue `ObjCProperty
let make_method_decl_info mdi body = {
Clang_ast_t.omdi_is_instance_method = mdi.Clang_ast_t.omdi_is_instance_method;
Clang_ast_t.omdi_result_type = mdi.Clang_ast_t.omdi_result_type;
@ -168,14 +194,23 @@ let make_name_decl name = {
Clang_ast_t.ni_qual_name = [name];
}
let make_general_decl_ref k decl_ptr name is_hidden qt = {
let make_decl_ref k decl_ptr name is_hidden qt_opt = {
Clang_ast_t.dr_kind = k;
Clang_ast_t.dr_decl_pointer = decl_ptr;
Clang_ast_t.dr_name = Some (make_name_decl name);
Clang_ast_t.dr_is_hidden = is_hidden ;
Clang_ast_t.dr_qual_type = Some (qt)
Clang_ast_t.dr_qual_type = qt_opt
}
let make_decl_ref_qt k decl_ptr name is_hidden qt =
make_decl_ref k decl_ptr name is_hidden (Some qt)
let make_decl_ref_no_qt k decl_ptr name is_hidden =
make_decl_ref k decl_ptr name is_hidden None
let make_decl_ref_invalid k name is_hidden qt =
make_decl_ref k (Ast_utils.get_invalid_pointer ()) name is_hidden (Some qt)
let make_decl_ref_self ptr qt = {
Clang_ast_t.dr_kind = `ImplicitParam;
Clang_ast_t.dr_decl_pointer = ptr;
@ -190,7 +225,7 @@ let make_decl_ref_expr_info decl_ref = {
}
let make_obj_c_ivar_ref_expr_info k ptr n qt = {
Clang_ast_t.ovrei_decl_ref = make_general_decl_ref k ptr n false qt;
Clang_ast_t.ovrei_decl_ref = make_decl_ref_qt k ptr n false qt;
Clang_ast_t.ovrei_pointer = Ast_utils.get_fresh_pointer ();
Clang_ast_t.ovrei_is_free_ivar = true;
}
@ -212,9 +247,8 @@ let make_self_field class_type di qt field_name =
let qt_class = create_qual_type class_type in
let expr_info = make_expr_info_with_objc_kind qt `ObjCProperty in
let stmt_info = make_stmt_info di in
let decl_ptr = Ast_utils.get_invalid_pointer() in
let cast_exp = make_cast_expr qt_class di (make_decl_ref_expr_info (make_decl_ref_self decl_ptr qt_class)) `ObjCProperty in
let obj_c_ivar_ref_expr_info = make_obj_c_ivar_ref_expr_info (`ObjCIvar) decl_ptr field_name qt in
let cast_exp = make_cast_expr qt_class di (make_decl_ref_expr_info (make_decl_ref_self di.di_pointer qt_class)) `ObjCProperty in
let obj_c_ivar_ref_expr_info = make_obj_c_ivar_ref_expr_info (`ObjCIvar) di.di_pointer field_name qt in
let ivar_ref_exp = ObjCIvarRefExpr(stmt_info, [cast_exp], expr_info, obj_c_ivar_ref_expr_info) in
ivar_ref_exp
@ -258,9 +292,20 @@ let make_expr_info qt =
Clang_ast_t.ei_object_kind = `ObjCProperty
}
let make_general_expr_info qt vk ok =
{
Clang_ast_t.ei_qual_type = qt;
Clang_ast_t.ei_value_kind = vk;
Clang_ast_t.ei_object_kind = ok
}
let make_ObjCBoolLiteralExpr stmt_info value =
let ei = make_expr_info (create_BOOL_type ()) in
ObjCBoolLiteralExpr((fresh_stmt_info stmt_info),[], ei, value)
let make_decl_ref_exp_var (var_name, var_qt, var_ptr) var_kind stmt_info =
let stmt_info = stmt_info_with_fresh_pointer stmt_info in
let decl_ref = make_general_decl_ref var_kind var_ptr var_name false var_qt in
let decl_ref = make_decl_ref_qt var_kind var_ptr var_name false var_qt in
let expr_info = make_expr_info var_qt in
make_decl_ref_exp stmt_info expr_info (make_decl_ref_expr_info decl_ref)
@ -272,7 +317,7 @@ let make_message_expr param_qt selector decl_ref_exp stmt_info add_cast =
[cast_expr]
else [decl_ref_exp] in
let obj_c_message_expr_info = make_obj_c_message_expr_info_instance selector in
let expr_info = make_expr_info param_qt in
let expr_info = make_expr_info_with_objc_kind param_qt `ObjCProperty in
ObjCMessageExpr (stmt_info, parameters, expr_info, obj_c_message_expr_info)
let make_compound_stmt stmts stmt_info =
@ -289,18 +334,18 @@ let make_next_object_exp stmt_info item items =
| DeclStmt (stmt_info, _, [VarDecl(di, name_info, var_type, _)]) ->
let var_name = name_info.Clang_ast_t.ni_name in
let decl_ptr = di.Clang_ast_t.di_pointer in
let decl_ref = make_general_decl_ref `Var decl_ptr var_name false var_type in
let decl_ref = make_decl_ref_qt `Var decl_ptr var_name false var_type in
let stmt_info_var = {
si_pointer = di.Clang_ast_t.di_pointer;
si_source_range = di.Clang_ast_t.di_source_range
} in
DeclRefExpr(stmt_info_var, [], (make_expr_info var_type), (make_decl_ref_expr_info decl_ref)),
DeclRefExpr(stmt_info_var, [], (make_expr_info_with_objc_kind var_type `ObjCProperty), (make_decl_ref_expr_info decl_ref)),
var_type
| _ -> assert false in
let message_call = make_message_expr (create_qual_type CFrontend_config.id_cl)
CFrontend_config.next_object items stmt_info false in
let boi = { Clang_ast_t.boi_kind = `Assign } in
make_binary_stmt var_decl_ref message_call stmt_info (make_expr_info var_type) boi
make_binary_stmt var_decl_ref message_call stmt_info (make_expr_info_with_objc_kind var_type `ObjCProperty) boi
let empty_var_decl = {
vdi_storage_class = None;
@ -317,7 +362,8 @@ let translate_dispatch_function block_name stmt_info stmt_list ei n =
try Utils.list_nth stmt_list (n + 1)
with Not_found -> assert false in
let block_name_info = make_name_decl block_name in
match block_expr with BlockExpr(bsi, bsl, bei, bd) ->
match block_expr with
| BlockExpr(bsi, bsl, bei, bd) ->
let qt = bei.Clang_ast_t.ei_qual_type in
let cast_info = { cei_cast_kind = `BitCast; cei_base_path =[]} in
let block_def = ImplicitCastExpr(stmt_info,[block_expr], bei, cast_info) in
@ -326,27 +372,11 @@ let translate_dispatch_function block_name stmt_info stmt_list ei n =
let var_decl_info = { empty_var_decl with vdi_init_expr = Some block_def } in
let block_var_decl = VarDecl(decl_info, block_name_info, ei.ei_qual_type, var_decl_info) in
let decl_stmt = DeclStmt(stmt_info,[], [block_var_decl]) in
let expr_info_call = {
Clang_ast_t.ei_qual_type = create_void_type ();
Clang_ast_t.ei_value_kind = `XValue;
Clang_ast_t.ei_object_kind = `Ordinary
} in
let expr_info_dre = {
Clang_ast_t.ei_qual_type = qt;
Clang_ast_t.ei_value_kind = `LValue;
Clang_ast_t.ei_object_kind = `Ordinary
} in
let decl_ref = {
dr_kind = `Var;
dr_decl_pointer = decl_info.di_pointer;
dr_name = Some block_name_info;
dr_is_hidden = false;
dr_qual_type = Some qt;
} in
let decl_ref_expr_info = {
drti_decl_ref = Some decl_ref;
drti_found_decl_ref = None
} in
let expr_info_call = make_general_expr_info (create_void_type ()) `XValue `Ordinary in
let expr_info_dre = make_expr_info_with_objc_kind qt `Ordinary in
let decl_ref = make_decl_ref_qt `Var stmt_info.si_pointer block_name false qt in
let decl_ref_expr_info = make_decl_ref_expr_info decl_ref in
let cast_info_call = { cei_cast_kind = `LValueToRValue; cei_base_path =[]} in
let decl_ref_exp = DeclRefExpr(stmt_info, [], expr_info_dre, decl_ref_expr_info) in
let stmt_call = ImplicitCastExpr(stmt_info, [decl_ref_exp], bei, cast_info_call) in
@ -354,6 +384,256 @@ let translate_dispatch_function block_name stmt_info stmt_list ei n =
CompoundStmt (stmt_info, [decl_stmt; call_block_var]), qt
| _ -> assert false (* when we call this function we have already checked that this cannot be possible *)
(* Create declaration statement: qt vname = iexp *)
let make_DeclStmt stmt_info di qt vname iexp =
let init_expr_opt, init_expr_l = match iexp with
| Some iexp' ->
let ie = create_implicit_cast_expr stmt_info [iexp'] qt `IntegralCast in
Some ie, [ie]
| None -> None, [] in
let var_decl = VarDecl(di, vname, qt, { empty_var_decl_info with Clang_ast_t.vdi_init_expr = init_expr_opt;}) in
DeclStmt(stmt_info, init_expr_l, [var_decl])
let build_OpaqueValueExpr si source_expr ei =
let opaque_value_expr_info = { Clang_ast_t.ovei_source_expr = Some source_expr } in
OpaqueValueExpr(si, [], ei, opaque_value_expr_info)
let pseudo_object_qt () =
create_qual_type CFrontend_config.pseudo_object_type
(* Create expression PseudoObjectExpr for 'o.m' *)
let build_PseudoObjectExpr qt_m o_cast_decl_ref_exp mname =
match o_cast_decl_ref_exp with
| ImplicitCastExpr(si, stmt_list, ei, cast_expr_info) ->
let ove = build_OpaqueValueExpr si o_cast_decl_ref_exp ei in
let ei_opre = make_expr_info (pseudo_object_qt ()) in
let obj_c_property_ref_expr_info = {
Clang_ast_t.oprei_kind =
`PropertyRef (make_decl_ref_no_qt `ObjCProperty si.si_pointer CFrontend_config.count false);
Clang_ast_t.oprei_is_super_receiver = false;
Clang_ast_t.oprei_is_messaging_getter = true;
Clang_ast_t.oprei_is_messaging_setter = false;
} in
let opre = ObjCPropertyRefExpr(si, [ove], ei_opre, obj_c_property_ref_expr_info) in
let ome = make_message_expr qt_m mname o_cast_decl_ref_exp si false in
let poe_ei = make_general_expr_info qt_m `LValue `Ordinary in
PseudoObjectExpr(si, [opre; ove; ome], poe_ei)
| _ -> assert false
let create_call stmt_info decl_pointer function_name qt parameters =
let expr_info_call = {
Clang_ast_t.ei_qual_type = create_void_type ();
Clang_ast_t.ei_value_kind = `XValue;
Clang_ast_t.ei_object_kind = `Ordinary
} in
let expr_info_dre = make_expr_info_with_objc_kind qt `Ordinary in
let decl_ref = make_decl_ref_qt `Function decl_pointer function_name false qt in
let decl_ref_info = make_decl_ref_expr_info decl_ref in
let decl_ref_exp = DeclRefExpr(stmt_info, [], expr_info_dre, decl_ref_info) in
let cast = create_implicit_cast_expr (fresh_stmt_info stmt_info) [decl_ref_exp] qt `FunctionToPointerDecay in
CallExpr(stmt_info, cast:: parameters, expr_info_call)
(* For a of type NSArray* Translate *)
(* [a enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL * stop) { *)
(* body_block *)
(* }; *)
(* ]; *)
(* as follows: *)
(* NSArray *objects = a; *)
(* void (^enumerateObjectsUsingBlock)(id, NSUInteger, BOOL* )= ^(id object, NSUInteger idx, BOOL* stop) { *)
(* body_block *)
(* }; *)
(* BOOL *stop = malloc(sizeof(BOOL)); *)
(* *stop = NO; *)
(* for (NSUInteger idx=0; idx<objects.count; idx++) { *)
(* id object= objects[idx]; *)
(* enumerateObjectsUsingBlock(object, idx, stop); *)
(* if ( *stop ==YES) break; *)
(* } *)
(* free(stop); *)
(* *)
let translate_block_enumerate block_name stmt_info stmt_list ei =
let rec get_name_pointers lp =
match lp with
| [] -> []
| ParmVarDecl(di, name, qt, _):: lp' ->
(name.Clang_ast_t.ni_name, di.Clang_ast_t.di_pointer, qt):: get_name_pointers lp'
| _ -> assert false in
let build_idx_decl pidx =
match pidx with
| ParmVarDecl(di_idx, name_idx, qt_idx, _) ->
let zero = create_integer_literal stmt_info "0" in
(* qt_idx idx = 0; *)
let idx_decl_stmt = make_DeclStmt (fresh_stmt_info stmt_info) di_idx qt_idx name_idx (Some zero) in
let idx_ei = make_expr_info qt_idx in
let idx_decl_ref = make_decl_ref_qt `Var di_idx.di_pointer name_idx.Clang_ast_t.ni_name false qt_idx in
let idx_drei = make_decl_ref_expr_info idx_decl_ref in
let idx_decl_ref_exp = make_decl_ref_exp stmt_info idx_ei idx_drei in
let idx_cast = create_implicit_cast_expr (fresh_stmt_info stmt_info) [idx_decl_ref_exp] qt_idx `LValueToRValue in
idx_decl_stmt, idx_decl_ref_exp, idx_cast, qt_idx
| _ -> assert false in
let cast_expr decl_ref qt =
let ei = make_expr_info qt in
let drei = make_decl_ref_expr_info decl_ref in
let decl_ref_exp = make_decl_ref_exp (fresh_stmt_info stmt_info) ei drei in
create_implicit_cast_expr (fresh_stmt_info stmt_info) [decl_ref_exp] qt `LValueToRValue in
(* build statement BOOL *stop = malloc(sizeof(BOOL)); *)
let build_stop pstop =
match pstop with
| ParmVarDecl(di, name, qt, _) ->
let qt_fun = create_void_unsigned_long_type () in
let parameter = UnaryExprOrTypeTraitExpr((fresh_stmt_info stmt_info), [],
make_expr_info (create_unsigned_long_type ()),
{ Clang_ast_t.uttei_kind = `SizeOf; Clang_ast_t.uttei_qual_type = Some (create_BOOL_type ()) }) in
let malloc = create_call (fresh_stmt_info stmt_info) di.di_pointer CFrontend_config.malloc qt_fun [parameter] in
let init_exp = create_implicit_cast_expr (fresh_stmt_info stmt_info) [malloc] qt `BitCast in
make_DeclStmt (fresh_stmt_info stmt_info) di qt name (Some init_exp)
| _ -> assert false in
(* BOOL *stop =NO; *)
let stop_equal_no pstop =
match pstop with
| ParmVarDecl(di, name, qt, _) ->
let decl_ref = make_decl_ref_qt `Var di.di_pointer name.Clang_ast_t.ni_name false qt in
let cast = cast_expr decl_ref qt in
let lhs = UnaryOperator((fresh_stmt_info stmt_info), [cast], ei, { uoi_kind = `Deref; uoi_is_postfix = true }) in
let bool_NO = make_ObjCBoolLiteralExpr stmt_info 0 in
BinaryOperator((fresh_stmt_info stmt_info), [lhs; bool_NO], ei, { boi_kind = `Assign })
| _ -> assert false in
(* build statement free(stop); *)
let free_stop pstop =
match pstop with
| ParmVarDecl(di, name, qt, _) ->
let qt_fun = create_void_void_type () in
let decl_ref = make_decl_ref_qt `Var di.di_pointer name.Clang_ast_t.ni_name false qt in
let cast = cast_expr decl_ref qt in
let parameter =
create_implicit_cast_expr (fresh_stmt_info stmt_info) [cast] (create_void_type ()) `BitCast in
create_call (fresh_stmt_info stmt_info) di.di_pointer CFrontend_config.free qt_fun [parameter]
| _ -> assert false in
(* idx<a.count *)
let bin_op pidx array_decl_ref_exp =
let idx_decl_stmt, idx_decl_ref_exp, idx_cast, idx_qt = build_idx_decl pidx in
let rhs = build_PseudoObjectExpr idx_qt array_decl_ref_exp CFrontend_config.count in
BinaryOperator((fresh_stmt_info stmt_info), [idx_cast; rhs], make_expr_info (create_int_type ()), { boi_kind = `LT }) in
(* idx++ *)
let un_op idx_decl_ref_expr qt_idx =
let idx_ei = make_expr_info qt_idx in
UnaryOperator((fresh_stmt_info stmt_info), [idx_decl_ref_expr], idx_ei, { uoi_kind = `PostInc; uoi_is_postfix = true }) in
let get_ei_from_cast cast =
match cast with
| ImplicitCastExpr(_, _, ei, _) -> ei
| _ -> assert false in
(* id object= objects[idx]; *)
let build_object_DeclStmt pobj decl_ref_expr_array decl_ref_expr_idx qt_idx =
match pobj with
| ParmVarDecl(di_obj, name_obj, qt_obj, _) ->
let poe_ei = make_general_expr_info qt_obj `LValue `Ordinary in
let ei_array = get_ei_from_cast decl_ref_expr_array in
let ove_array = build_OpaqueValueExpr (fresh_stmt_info stmt_info) decl_ref_expr_array ei_array in
let ei_idx = get_ei_from_cast decl_ref_expr_idx in
let ove_idx = build_OpaqueValueExpr (fresh_stmt_info stmt_info) decl_ref_expr_idx ei_idx in
let objc_sre = ObjCSubscriptRefExpr((fresh_stmt_info stmt_info), [ove_array; ove_idx],
make_expr_info (pseudo_object_qt ()),
{ osrei_kind =`ArraySubscript; osrei_getter = None; osrei_setter = None; }) in
let obj_c_message_expr_info = { omei_selector = CFrontend_config.object_at_indexed_subscript_m; omei_receiver_kind =`Instance } in
let ome = ObjCMessageExpr((fresh_stmt_info stmt_info), [ove_array; ove_idx], poe_ei, obj_c_message_expr_info) in
let pseudo_obj_expr = PseudoObjectExpr((fresh_stmt_info stmt_info), [objc_sre; ove_array; ove_idx; ome], poe_ei) in
let vdi = { empty_var_decl_info with vdi_init_expr = Some (pseudo_obj_expr) } in
let var_decl = VarDecl(di_obj, name_obj, qt_obj, vdi) in
DeclStmt((fresh_stmt_info stmt_info), [pseudo_obj_expr], [var_decl])
| _ -> assert false in
(* NSArray *objects = a *)
let objects_array_DeclStmt init =
let di = { empty_decl_info with Clang_ast_t.di_pointer = Ast_utils.get_fresh_pointer () } in
let qt = create_qual_type CFrontend_config.ns_array_ptr in
(* init should be ImplicitCastExpr of array a *)
let vdi = { empty_var_decl_info with vdi_init_expr = Some (init) } in
let var_decl = VarDecl(di, make_name_decl CFrontend_config.objects, qt, vdi) in
DeclStmt((fresh_stmt_info stmt_info), [init], [var_decl]), [(CFrontend_config.objects, di.Clang_ast_t.di_pointer, qt)] in
let make_object_cast_decl_ref_expr objects =
match objects with
| DeclStmt(si, _, [VarDecl(di, name, qt, vdi)]) ->
let decl_ref = make_decl_ref_qt `Var si.si_pointer name.Clang_ast_t.ni_name false qt in
cast_expr decl_ref qt
| _ -> assert false in
let build_cast_decl_ref_expr_from_parm p =
match p with
| ParmVarDecl(di, name, qt, _) ->
let decl_ref = make_decl_ref_qt `Var di.di_pointer name.Clang_ast_t.ni_name false qt in
cast_expr decl_ref qt
| _ -> assert false in
let make_block_decl be =
match be with
| BlockExpr(bsi, _, bei, _) ->
let di = { empty_decl_info with Clang_ast_t.di_pointer = Ast_utils.get_fresh_pointer () } in
let vdi = { empty_var_decl_info with vdi_init_expr = Some (be) } in
let var_decl = VarDecl(di, make_name_decl block_name, bei.Clang_ast_t.ei_qual_type, vdi) in
DeclStmt(bsi, [be], [var_decl]), [(block_name, di.Clang_ast_t.di_pointer, bei.Clang_ast_t.ei_qual_type)]
| _ -> assert false in
let make_block_call block_qt object_cast idx_cast stop_cast =
let decl_ref = make_decl_ref_invalid `Var block_name false block_qt in
let fun_cast = cast_expr decl_ref block_qt in
let ei_call = make_expr_info (create_void_type ()) in
CallExpr((fresh_stmt_info stmt_info), [fun_cast; object_cast; idx_cast; stop_cast], ei_call) in
(* build statement "if (stop) break;" *)
let build_if_stop stop_cast =
let bool_qt = create_BOOL_type () in
let ei = make_expr_info bool_qt in
let unary_op = UnaryOperator((fresh_stmt_info stmt_info), [stop_cast], ei, { uoi_kind = `Deref; uoi_is_postfix = true }) in
let cond = create_implicit_cast_expr (fresh_stmt_info stmt_info) [unary_op] bool_qt `LValueToRValue in
let break_stmt = BreakStmt((fresh_stmt_info stmt_info),[]) in
IfStmt((fresh_stmt_info stmt_info), [dummy_stmt (); cond; break_stmt; dummy_stmt ()]) in
let translate params array_cast_decl_ref_exp block_decl block_qt =
match params with
| [pobj; pidx; pstop] ->
let objects_decl, op = objects_array_DeclStmt array_cast_decl_ref_exp in
let decl_stop = build_stop pstop in
let assign_stop = stop_equal_no pstop in
let objects = make_object_cast_decl_ref_expr objects_decl in
let idx_decl_stmt, idx_decl_ref_exp, idx_cast, qt_idx = build_idx_decl pidx in
let guard = bin_op pidx objects in
let incr = un_op idx_decl_ref_exp qt_idx in
let obj_assignment = build_object_DeclStmt pobj objects idx_cast qt_idx in
let object_cast = build_cast_decl_ref_expr_from_parm pobj in
let stop_cast = build_cast_decl_ref_expr_from_parm pstop in
let call_block = make_block_call block_qt object_cast idx_cast stop_cast in
let if_stop = build_if_stop stop_cast in
let free_stop = free_stop pstop in
[ objects_decl; block_decl; decl_stop; assign_stop;
ForStmt(stmt_info, [idx_decl_stmt; dummy_stmt (); guard; incr;
CompoundStmt(stmt_info, [obj_assignment; call_block; if_stop])]); free_stop], op
| _ -> assert false in
match stmt_list with
| [s; BlockExpr(_, _, bei, BlockDecl(_, _, _, bdi)) as be] ->
let block_decl, bv = make_block_decl be in
let vars_to_register = get_name_pointers bdi.Clang_ast_t.bdi_parameters in
let translated_stmt, op = translate bdi.Clang_ast_t.bdi_parameters s block_decl bei.Clang_ast_t.ei_qual_type in
CompoundStmt(stmt_info, translated_stmt), vars_to_register@op@bv
| _ -> (* When it is not the method we expect with only one parameter, we don't translate *)
Printing.log_out "WARNING: Block Enumeration called at %s not translated." (Clang_ast_j.string_of_stmt_info stmt_info);
CompoundStmt(stmt_info, stmt_list), []
(* We translate the logical negation of an integer with a conditional*)
(* !x <=> x?0:1 *)
let trans_negation_with_conditional stmt_info expr_info stmt_list =
@ -367,7 +647,7 @@ let create_call stmt_info decl_pointer function_name qt parameters =
Clang_ast_t.ei_object_kind = `Ordinary
} in
let expr_info_dre = make_expr_info_with_objc_kind qt `Ordinary in
let decl_ref = make_general_decl_ref `Function decl_pointer function_name false qt in
let decl_ref = make_decl_ref_qt `Function decl_pointer function_name false qt in
let decl_ref_info = make_decl_ref_expr_info decl_ref in
let decl_ref_exp = DeclRefExpr(stmt_info, [], expr_info_dre, decl_ref_info) in
CallExpr(stmt_info, decl_ref_exp:: parameters, expr_info_call)
@ -376,7 +656,7 @@ let create_assume_not_null_call decl_info var_name var_type =
let stmt_info = stmt_info_with_fresh_pointer (make_stmt_info decl_info) in
let boi = { Clang_ast_t.boi_kind = `NE } in
let decl_ptr = Ast_utils.get_invalid_pointer () in
let decl_ref = make_general_decl_ref `Var decl_ptr var_name false var_type in
let decl_ref = make_decl_ref_qt `Var decl_ptr var_name false var_type in
let stmt_info_var = dummy_stmt_info () in
let decl_ref_info = make_decl_ref_expr_info decl_ref in
let var_decl_ref = DeclRefExpr(stmt_info_var, [], (make_expr_info var_type), decl_ref_info) in
@ -389,6 +669,6 @@ let create_assume_not_null_call decl_info var_name var_type =
let cast_info_call = { cei_cast_kind = `LValueToRValue; cei_base_path = [] } in
let decl_ref_exp_cast = ImplicitCastExpr(stmt_info, [var_decl_ref], expr_info, cast_info_call) in
let null_expr = create_integer_literal stmt_info "0" in
let bin_op = make_binary_stmt decl_ref_exp_cast null_expr stmt_info (make_expr_info var_type) boi in
let bin_op = make_binary_stmt decl_ref_exp_cast null_expr stmt_info (make_lvalue_obc_prop_expr_info var_type) boi in
let parameters = [bin_op] in
create_call stmt_info var_decl_ptr (Procname.to_string SymExec.ModelBuiltins.__infer_assume) (create_void_type ()) parameters

@ -31,10 +31,12 @@ val make_stmt_info : decl_info -> stmt_info
val make_method_decl_info : obj_c_method_decl_info -> stmt -> obj_c_method_decl_info
val make_general_decl_ref : decl_kind -> pointer -> string -> bool -> qual_type -> decl_ref
val make_decl_ref_qt : decl_kind -> pointer -> string -> bool -> qual_type -> decl_ref
val make_decl_ref_expr_info : decl_ref -> decl_ref_expr_info
val make_general_expr_info : qual_type -> value_kind -> object_kind -> expr_info
val make_expr_info : qual_type -> expr_info
val make_cast_expr : qual_type -> decl_info -> decl_ref_expr_info -> object_kind -> stmt
@ -63,6 +65,8 @@ val make_obj_c_message_expr_info_instance : string -> obj_c_message_expr_info
val translate_dispatch_function : string -> stmt_info -> stmt list -> expr_info -> int -> stmt * qual_type
val translate_block_enumerate : string -> stmt_info -> stmt list -> expr_info -> stmt * (string * string* qual_type) list
(* We translate the logical negation of an integer with a conditional*)
(* !x <=> x?0:1 *)
val trans_negation_with_conditional : stmt_info -> expr_info -> stmt list -> stmt

@ -15,6 +15,8 @@ let testing_mode = ref false
let array_with_objects_count_m = "arrayWithObjects:count:"
let object_at_indexed_subscript_m = "objectAtIndexedSubscript:"
let dict_with_objects_and_keys_m = "dictionaryWithObjectsAndKeys:"
let string_with_utf8_m = "stringWithUTF8String:"
@ -35,6 +37,8 @@ let alloc = "alloc"
let malloc = "malloc"
let free = "free"
let static = "static"
let source_file : string option ref = ref None
@ -131,3 +135,13 @@ let handleFailureInFunction = "handleFailureInFunction:file:lineNumber:descripti
let fbAssertWithSignalAndLogFunctionHelper = "FBAssertWithSignalAndLogFunctionHelper"
let nonnull_attribute = "__nonnull"
let pseudo_object_type = "<pseudo-object type>"
let count = "count"
let objects = "objects"
let ns_array_ptr = "NSArray *"
let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:"

@ -63,10 +63,14 @@ val alloc : string
val malloc : string
val free : string
val static : string
val array_with_objects_count_m : string
val object_at_indexed_subscript_m : string
val dict_with_objects_and_keys_m : string
val emtpy_name_category : string
@ -128,3 +132,13 @@ val handleFailureInMethod : string
val handleFailureInFunction : string
val nonnull_attribute : string
val pseudo_object_type : string
val count : string
val objects : string
val ns_array_ptr : string
val enumerateObjectsUsingBlock : string

@ -112,7 +112,7 @@ struct
let add_method tenv cg cfg class_decl_opt procname namespace instrs is_objc_method is_instance
captured_vars is_anonym_block param_decls attributes =
Printing.log_out
"\n\n>>---------- ADDING METHOD: '%s' ---------<<\n" (Procname.to_string procname);
"\n\n>>---------- ADDING METHOD: '%s' ---------<<\n@." (Procname.to_string procname);
try
(match Cfg.Procdesc.find_from_name cfg procname with
| Some procdesc ->
@ -127,7 +127,7 @@ struct
Cfg.Procdesc.append_locals procdesc local_vars;
Cfg.Node.add_locals_ret_declaration start_node local_vars;
Printing.log_out
"\n\n>>---------- Start translating the function: '%s' ---------<<"
"\n\n>>---------- Start translating body of function: '%s' ---------<<\n@."
(Procname.to_string procname);
let nonnull_assume_calls = add_assume_not_null_calls param_decls in
let instrs' = instrs@nonnull_assume_calls attributes in
@ -191,7 +191,7 @@ struct
let prop_methods = ObjcProperty_decl.make_getter_setter cfg curr_class decl_info property_impl_decl_info in
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) prop_methods
| EmptyDecl _ | ObjCIvarDecl _ -> ()
| EmptyDecl _ | ObjCIvarDecl _ | ObjCPropertyDecl _ -> ()
| d -> Printing.log_err
"\nWARNING: found Method Declaration '%s' skipped. NEED TO BE FIXED\n\n" (Ast_utils.string_of_decl d);
()

@ -158,8 +158,7 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method =
(* Captured variables for blocks are treated as parameters *)
let formals = captured_str @formals in
let source_range = CMethod_signature.ms_get_loc ms in
Printing.log_out
"\n\n>>------------------------- Start creating a new procdesc for function: '%s' ---------<<\n" pname;
Printing.log_out "\nCreating a new procdesc for function: '%s'\n@." pname;
let loc_start = CLocation.get_sil_location_from_range source_range true in
let loc_exit = CLocation.get_sil_location_from_range source_range false in
let ret_type = get_return_type tenv ms in

@ -143,8 +143,9 @@ struct
(* At the end of block translation, we need to get the proirity back.*)
(* the parameter f will be called with function instruction *)
let exec_with_block_priority_exception f trans_state e stmt_info =
if (is_block_expr e) && (PriorityNode.own_priority_node trans_state.priority stmt_info) then
f { trans_state with priority = Free } e
if (is_block_expr e) && (PriorityNode.own_priority_node trans_state.priority stmt_info) then (
Printing.log_out "Translating block expression by freeing the priority";
f { trans_state with priority = Free } e)
else f trans_state e
(* This is the standard way of dealing with self:Class or a call [a class]. We translate it as sizeof(<type pf a>) *)
@ -274,7 +275,8 @@ struct
{ empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes }
let declRefExpr_trans trans_state stmt_info expr_info decl_ref_expr_info d =
Printing.log_out "Passing from DeclRefExpr '%s' \n" stmt_info.Clang_ast_t.si_pointer;
Printing.log_out "Passing from DeclRefExpr '%s' priority node free = '%s'\n@." stmt_info.Clang_ast_t.si_pointer
(string_of_bool (PriorityNode.is_priority_free trans_state));
let context = trans_state.context in
let typ = CTypes_decl.qual_type_to_sil_type context.tenv expr_info.Clang_ast_t.ei_qual_type in
let name = get_name_decl_ref_exp_info decl_ref_expr_info stmt_info in
@ -543,8 +545,7 @@ struct
(Procname.to_string pn) <> CFrontend_config.builtin_object_size
| _ -> true in
let params_stmt = if should_translate_args then
CTrans_utils.assign_default_params params_stmt callee_pname_opt
else [] in
CTrans_utils.assign_default_params params_stmt callee_pname_opt else [] in
let res_trans_par =
let l = list_map (fun i -> exec_with_self_exception instruction trans_state_param i) params_stmt in
let rt = collect_res_trans (res_trans_callee :: l) in
@ -600,7 +601,8 @@ struct
| _ -> assert false) (* by construction of red_id, we cannot be in this case *)
and objCMessageExpr_trans trans_state si obj_c_message_expr_info stmt_list expr_info =
Printing.log_out "Passing from ObjMessageExpr '%s'.\n" si.Clang_ast_t.si_pointer;
Printing.log_out "Passing from ObjMessageExpr '%s' priority node free ='%s'.\n@." si.Clang_ast_t.si_pointer
(string_of_bool (PriorityNode.is_priority_free trans_state));
let context = trans_state.context in
let parent_line_number = trans_state.parent_line_number in
let sil_loc = get_sil_location si parent_line_number context in
@ -656,8 +658,8 @@ struct
instrs = res_trans_par.instrs@instr_block_param@[stmt_call];
exps =[]
} in
let res_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp in
let res_trans_to_parent = (
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp) in
(match ret_id with
| [] -> { res_trans_to_parent with exps = [] }
| [ret_id'] -> { res_trans_to_parent with exps = [(Sil.Var ret_id', method_type)] }
@ -680,6 +682,29 @@ struct
list_iter (fun n -> Cfg.Node.append_instrs_temps n [Sil.Nullify(pvar, loc, true)] []) preds;
res_state
and block_enumeration_trans trans_state stmt_info stmt_list ei =
let declare_nullify_vars loc res_state roots preds (pvar, typ) =
(* Add declare locals to the first node *)
list_iter (fun n -> Cfg.Node.prepend_instrs_temps n [Sil.Declare_locals([(pvar, typ)], loc)] []) roots;
(* Add nullify of the temp block var to the last node (predecessor or the successor nodes)*)
list_iter (fun n -> Cfg.Node.append_instrs_temps n [Sil.Nullify(pvar, loc, true)] []) preds in
Printing.log_out "\n Call to a block enumeration function treated as special case...\n@.";
let procname = Cfg.Procdesc.get_proc_name trans_state.context.procdesc in
let pvar = CFrontend_utils.General_utils.get_next_block_pvar procname in
let transformed_stmt, vars_to_register =
Ast_expressions.translate_block_enumerate (Sil.pvar_to_string pvar) stmt_info stmt_list ei in
let pvars_types = list_map (fun (v, pointer, qt) ->
let pvar = Sil.mk_pvar (Mangled.from_string v) procname in
let typ = CTypes_decl.qual_type_to_sil_type trans_state.context.tenv qt in
CContext.LocalVars.add_pointer_var pointer pvar trans_state.context;
(pvar, typ)) vars_to_register in
let loc = get_sil_location stmt_info trans_state.parent_line_number trans_state.context in
let res_state = instruction trans_state transformed_stmt in
let preds = list_flatten (list_map (fun n -> Cfg.Node.get_preds n) trans_state.succ_nodes) in
list_iter (declare_nullify_vars loc res_state res_state.root_nodes preds) pvars_types;
res_state
and compoundStmt_trans trans_state stmt_info stmt_list =
Printing.log_out "Passing from CompoundStmt '%s'.\n" stmt_info.Clang_ast_t.si_pointer;
let line_number = get_line stmt_info trans_state.parent_line_number in
@ -1282,7 +1307,6 @@ struct
let node = list_hd next_node in
Cfg.Node.append_instrs_temps node instrs ids;
list_iter (fun n -> Cfg.Node.set_succs_exn n [node] []) leaf_nodes;
let root_nodes = if (list_length root_nodes) = 0 then next_node else root_nodes in
{ root_nodes = root_nodes; leaf_nodes =[]; ids = ids; instrs = instrs; exps = [(Sil.Lvar pvar, ie_typ)]}
) else { root_nodes = root_nodes; leaf_nodes =[]; ids = ids; instrs = instrs; exps =[(Sil.Lvar pvar, ie_typ)]}) in
@ -1329,7 +1353,8 @@ struct
(* For OpaqueValueExpr we return the translation generated from its source expression*)
and opaqueValueExpr_trans trans_state stmt_info opaque_value_expr_info =
Printing.log_out "Passing from OpaqueValueExpr '%s' \n" stmt_info.Clang_ast_t.si_pointer;
Printing.log_out "Passing from OpaqueValueExpr '%s' priority node free ='%s'\n@." stmt_info.Clang_ast_t.si_pointer
(string_of_bool (PriorityNode.is_priority_free trans_state));
(match opaque_value_expr_info.Clang_ast_t.ovei_source_expr with
| Some stmt -> instruction trans_state stmt
| _ -> assert false)
@ -1351,7 +1376,8 @@ struct
and pseudoObjectExpr_trans trans_state stmt_info stmt_list =
let line_number = get_line stmt_info trans_state.parent_line_number in
let trans_state' = { trans_state with parent_line_number = line_number } in
Printing.log_out "Passing from PseudoObjectExpr '%s' \n" stmt_info.Clang_ast_t.si_pointer;
Printing.log_out "Passing from PseudoObjectExpr '%s' priority node free ='%s' \n" stmt_info.Clang_ast_t.si_pointer
(string_of_bool (PriorityNode.is_priority_free trans_state));
let rec do_semantic_elements el =
(match el with
| OpaqueValueExpr _ :: el' -> do_semantic_elements el'
@ -1366,7 +1392,8 @@ struct
and cast_exprs_trans trans_state stmt_info stmt_list expr_info cast_expr_info is_objc_bridged =
let context = trans_state.context in
let pln = trans_state.parent_line_number in
Printing.log_out "Passing from CastExpr '%s' \n" stmt_info.Clang_ast_t.si_pointer;
Printing.log_out "Passing from CastExpr '%s' priority node free = '%s' \n" stmt_info.Clang_ast_t.si_pointer
(string_of_bool (PriorityNode.is_priority_free trans_state));
let sil_loc = get_sil_location stmt_info pln context in
let stmt = extract_stmt_from_singleton stmt_list
"WARNING: In CastExpr There must be only one stmt defining the expression to be cast.\n" in
@ -1652,7 +1679,10 @@ struct
callExpr_trans trans_state stmt_info stmt_list ei)
| ObjCMessageExpr(stmt_info, stmt_list, expr_info, obj_c_message_expr_info) ->
objCMessageExpr_trans trans_state stmt_info obj_c_message_expr_info stmt_list expr_info
if is_block_enumerate_function obj_c_message_expr_info then
block_enumeration_trans trans_state stmt_info stmt_list expr_info
else
objCMessageExpr_trans trans_state stmt_info obj_c_message_expr_info stmt_list expr_info
| CompoundStmt (stmt_info, stmt_list) ->
(* No node for this statement. We just collect its statement list*)

@ -194,8 +194,12 @@ struct
let try_claim_priority_node trans_state stmt_info =
match trans_state.priority with
| Free -> { trans_state with priority = Busy stmt_info.Clang_ast_t.si_pointer }
| _ -> trans_state
| Free ->
Printing.log_out "Priority is free. Locking priority node in %s\n@." stmt_info.Clang_ast_t.si_pointer;
{ trans_state with priority = Busy stmt_info.Clang_ast_t.si_pointer }
| _ ->
Printing.log_out "Priority busy in %s. No claim possible\n@." stmt_info.Clang_ast_t.si_pointer;
trans_state
let is_priority_free trans_state =
match trans_state.priority with
@ -683,3 +687,6 @@ let assign_default_params params_stmt callee_pname_opt =
Printing.log_err "Param count doesn't match %s\n" (Procname.to_string callee_pname);
params_stmt
| Not_found -> params_stmt
let is_block_enumerate_function mei =
mei.Clang_ast_t.omei_selector = CFrontend_config.enumerateObjectsUsingBlock

@ -202,3 +202,5 @@ val is_logical_negation_of_int : Sil.tenv -> Clang_ast_t.expr_info -> Clang_ast_
val is_dispatch_function : Clang_ast_t.stmt list -> int option
val assign_default_params : Clang_ast_t.stmt list -> Procname.t option -> Clang_ast_t.stmt list
val is_block_enumerate_function : Clang_ast_t.obj_c_message_expr_info -> bool

@ -97,7 +97,7 @@ let string_type_to_sil_type tenv s =
let t = CTypes_parser.parse (Ast_lexer.token) lexbuf in
Printing.log_out
" ...Parsed. Translated with sil TYPE '%a'@." (Sil.pp_typ_full pe_text) t;
t
t
with Parsing.Parse_error -> (
Printing.log_stats
"\nXXXXXXX PARSE ERROR for string '%s'. RETURNING Void.TODO@.@." s;
@ -116,7 +116,6 @@ let opt_type_to_sil_type tenv opt_type =
| `Type(s) -> qual_type_to_sil_type_no_expansions tenv (Ast_expressions.create_qual_type s)
| `NoType -> Sil.Tvoid
let parse_func_type name func_type =
try
let lexbuf = Lexing.from_string func_type in
@ -202,7 +201,7 @@ and do_record_declaration tenv namespace decl_info name opt_type decl_list decl_
Printing.log_out "ADDING: RecordDecl for '%s'" name;
Printing.log_out " pointer= '%s'\n" decl_info.Clang_ast_t.di_pointer;
if not record_decl_info.Clang_ast_t.rdi_is_complete_definition then
Printing.log_err " ...Warning, definition incomplete. The full definition will probably be later \n";
Printing.log_err " ...Warning, definition incomplete. The full definition will probably be later \n@.";
let typ = get_declaration_type tenv namespace decl_info name opt_type decl_list decl_context_info record_decl_info in
let typ = expand_structured_type tenv typ in
add_struct_to_tenv tenv typ

@ -94,7 +94,7 @@ let lookup_var stmt_info context pointer var_name kind =
try
lookup_var_static_globals context var_name
with Not_found ->
(Printing.log_out "Looking on later-defined decls for '%s'\n" var_name;
(Printing.log_out "Looking on later-defined decls for '%s' with pointer '%s' \n" var_name stmt_info.Clang_ast_t.si_pointer;
let decl_list = !CFrontend_config.global_translation_unit_decls in
lookup_ahead_for_vardecl context pointer var_name kind decl_list )

@ -306,7 +306,7 @@ let make_getter_setter cfg curr_class decl_info property_impl_decl_info =
| _ -> false) in
let decl_ptr = Ast_utils.get_invalid_pointer () in
let drti_decl_ref' =
Ast_expressions.make_general_decl_ref (`ParmVar) decl_ptr param_name is_hidden qt_param in
Ast_expressions.make_decl_ref_qt (`ParmVar) decl_ptr param_name is_hidden qt_param in
let decl_ref_expr_info' = Ast_expressions.make_decl_ref_expr_info drti_decl_ref' in
let expr_info = Ast_expressions.make_expr_info qt_param in
let stmt_info = Ast_expressions.make_stmt_info dummy_info in

@ -0,0 +1,212 @@
digraph iCFG {
52 [label="52: DeclStmt \n n$47=_fun___objc_alloc_no_fail(sizeof(class NSArray ):class NSArray *) [line 30]\n n$45=_fun_NSArray_init(n$47:class NSArray *) virtual [line 30]\n *&a:class NSArray *=n$45 [line 30]\n REMOVE_TEMPS(n$45,n$47); [line 30]\n " shape="box"]
52 -> 51 ;
51 [label="51: DeclStmt \n n$44=*&a:class NSArray * [line 32]\n *&objects:class NSArray *=n$44 [line 32]\n REMOVE_TEMPS(n$44); [line 32]\n NULLIFY(&a,false); [line 32]\n " shape="box"]
51 -> 44 ;
50 [label="50: BinaryOperatorStmt: Assign \n NULLIFY(&ShouldStop,false); [line 40]\n n$42=*&stop:BOOL * [line 40]\n *n$42:_Bool =1 [line 40]\n REMOVE_TEMPS(n$42); [line 40]\n NULLIFY(&stop,false); [line 40]\n APPLY_ABSTRACTION; [line 40]\n " shape="box"]
50 -> 47 ;
49 [label="49: Prune (false branch) \n n$41=*&ShouldStop:int [line 39]\n PRUNE((n$41 == 0), false); [line 39]\n REMOVE_TEMPS(n$41); [line 39]\n APPLY_ABSTRACTION; [line 39]\n " shape="invhouse"]
49 -> 47 ;
48 [label="48: Prune (true branch) \n n$41=*&ShouldStop:int [line 39]\n PRUNE((n$41 != 0), true); [line 39]\n REMOVE_TEMPS(n$41); [line 39]\n " shape="invhouse"]
48 -> 50 ;
47 [label="47: + \n NULLIFY(&ShouldStop,false); [line 39]\n NULLIFY(&stop,false); [line 39]\n " ]
47 -> 46 ;
46 [label="46: Exit __objc_anonymous_block_MyBlock_array_trans______2 \n " color=yellow style=filled]
45 [label="45: Start __objc_anonymous_block_MyBlock_array_trans______2\nFormals: object:struct objc_object * idx:unsigned long stop:BOOL *\nLocals: ShouldStop:int \n DECLARE_LOCALS(&return,&ShouldStop); [line 35]\n NULLIFY(&idx,false); [line 35]\n NULLIFY(&object,false); [line 35]\n " color=yellow style=filled]
45 -> 48 ;
45 -> 49 ;
44 [label="44: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_MyBlock_array_trans______2); [line 35]\n n$43=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_MyBlock_array_trans______2 ):class __objc_anonymous_block_MyBlock_array_trans______2 *) [line 35]\n *&__objc_anonymous_block_MyBlock_array_trans______2:class __objc_anonymous_block_MyBlock_array_trans______2 =n$43 [line 35]\n *&enumerateObjectsUsingBlock:_fn_ (*)=(_fun___objc_anonymous_block_MyBlock_array_trans______2) [line 35]\n REMOVE_TEMPS(n$43); [line 35]\n " shape="box"]
44 -> 43 ;
43 [label="43: DeclStmt \n n$40=_fun_malloc_no_fail(sizeof(_Bool ):_Bool ) [line 43]\n *&stop:BOOL *=n$40 [line 43]\n REMOVE_TEMPS(n$40); [line 43]\n " shape="box"]
43 -> 42 ;
42 [label="42: BinaryOperatorStmt: Assign \n n$39=*&stop:BOOL * [line 44]\n *n$39:_Bool =0 [line 44]\n REMOVE_TEMPS(n$39); [line 44]\n " shape="box"]
42 -> 31 ;
41 [label="41: DeclStmt \n n$37=*&objects:class NSArray * [line 49]\n n$38=*&idx:unsigned long [line 49]\n n$36=_fun_NSArray_objectAtIndexedSubscript:(n$37:class NSArray *,n$38:unsigned long ) virtual [line 49]\n *&object:struct objc_object *=n$36 [line 49]\n REMOVE_TEMPS(n$36,n$37,n$38); [line 49]\n " shape="box"]
41 -> 40 ;
40 [label="40: Call n$32 \n n$32=*&enumerateObjectsUsingBlock:_fn_ (*) [line 50]\n n$33=*&object:struct objc_object * [line 50]\n n$34=*&idx:unsigned long [line 50]\n n$35=*&stop:BOOL * [line 50]\n n$32(n$33:struct objc_object *,n$34:unsigned long ,n$35:BOOL *) [line 50]\n REMOVE_TEMPS(n$32,n$33,n$34,n$35); [line 50]\n NULLIFY(&object,false); [line 50]\n " shape="box"]
40 -> 37 ;
39 [label="39: Prune (false branch) \n PRUNE(((n$31 == 1) == 0), false); [line 51]\n REMOVE_TEMPS(n$30,n$31); [line 51]\n " shape="invhouse"]
39 -> 36 ;
38 [label="38: Prune (true branch) \n PRUNE(((n$31 == 1) != 0), true); [line 51]\n REMOVE_TEMPS(n$30,n$31); [line 51]\n APPLY_ABSTRACTION; [line 51]\n " shape="invhouse"]
38 -> 29 ;
37 [label="37: BinaryOperatorStmt: EQ \n n$30=*&stop:BOOL * [line 51]\n n$31=*n$30:_Bool [line 51]\n " shape="box"]
37 -> 38 ;
37 -> 39 ;
36 [label="36: + \n " ]
36 -> 32 ;
35 [label="35: Prune (false branch) \n PRUNE(((n$27 < n$28) == 0), false); [line 46]\n REMOVE_TEMPS(n$27,n$28,n$29); [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="invhouse"]
35 -> 29 ;
34 [label="34: Prune (true branch) \n PRUNE(((n$27 < n$28) != 0), true); [line 46]\n REMOVE_TEMPS(n$27,n$28,n$29); [line 46]\n " shape="invhouse"]
34 -> 41 ;
33 [label="33: BinaryOperatorStmt: LT \n n$27=*&idx:unsigned long [line 46]\n n$29=*&objects:class NSArray * [line 46]\n n$28=_fun_NSArray_count(n$29:class NSArray *) virtual [line 46]\n " shape="box"]
33 -> 34 ;
33 -> 35 ;
32 [label="32: UnaryOperator \n n$26=*&idx:unsigned long [line 46]\n *&idx:unsigned long =(n$26 + 1) [line 46]\n REMOVE_TEMPS(n$26); [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="box"]
32 -> 30 ;
31 [label="31: DeclStmt \n *&idx:unsigned long =0 [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="box"]
31 -> 30 ;
30 [label="30: + \n " ]
30 -> 33 ;
29 [label="29: Call _fun_free \n NULLIFY(&enumerateObjectsUsingBlock,false); [line 53]\n NULLIFY(&idx,false); [line 53]\n NULLIFY(&objects,false); [line 53]\n n$25=*&stop:BOOL * [line 53]\n _fun_free(n$25:void *) [line 53]\n REMOVE_TEMPS(n$25); [line 53]\n NULLIFY(&__objc_anonymous_block_MyBlock_array_trans______2,true); [line 53]\n NULLIFY(&stop,false); [line 53]\n APPLY_ABSTRACTION; [line 53]\n " shape="box"]
29 -> 28 ;
28 [label="28: Exit MyBlock_array_trans \n " color=yellow style=filled]
27 [label="27: Start MyBlock_array_trans\nFormals: self:class MyBlock *\nLocals: a:class NSArray * objects:class NSArray * enumerateObjectsUsingBlock:_fn_ (*) stop:BOOL * idx:unsigned long object:struct objc_object * \n DECLARE_LOCALS(&return,&a,&objects,&enumerateObjectsUsingBlock,&stop,&idx,&object); [line 28]\n NULLIFY(&a,false); [line 28]\n NULLIFY(&enumerateObjectsUsingBlock,false); [line 28]\n NULLIFY(&idx,false); [line 28]\n NULLIFY(&object,false); [line 28]\n NULLIFY(&objects,false); [line 28]\n NULLIFY(&self,false); [line 28]\n NULLIFY(&stop,false); [line 28]\n " color=yellow style=filled]
27 -> 52 ;
26 [label="26: DeclStmt \n n$24=_fun___objc_alloc_no_fail(sizeof(class NSArray ):class NSArray *) [line 14]\n n$22=_fun_NSArray_init(n$24:class NSArray *) virtual [line 14]\n *&a:class NSArray *=n$22 [line 14]\n REMOVE_TEMPS(n$22,n$24); [line 14]\n " shape="box"]
26 -> 25 ;
25 [label="25: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_MyBlock_array______1); [line 15]\n DECLARE_LOCALS(&objects); [line 15]\n DECLARE_LOCALS(&stop); [line 15]\n DECLARE_LOCALS(&idx); [line 15]\n DECLARE_LOCALS(&object); [line 15]\n n$21=*&a:class NSArray * [line 15]\n *&objects:class NSArray *=n$21 [line 15]\n REMOVE_TEMPS(n$21); [line 15]\n NULLIFY(&a,false); [line 15]\n " shape="box"]
25 -> 18 ;
24 [label="24: BinaryOperatorStmt: Assign \n NULLIFY(&ShouldStop,false); [line 22]\n n$19=*&stop:BOOL * [line 22]\n *n$19:_Bool =1 [line 22]\n REMOVE_TEMPS(n$19); [line 22]\n NULLIFY(&stop,false); [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"]
24 -> 21 ;
23 [label="23: Prune (false branch) \n n$18=*&ShouldStop:int [line 20]\n PRUNE((n$18 == 0), false); [line 20]\n REMOVE_TEMPS(n$18); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="invhouse"]
23 -> 21 ;
22 [label="22: Prune (true branch) \n n$18=*&ShouldStop:int [line 20]\n PRUNE((n$18 != 0), true); [line 20]\n REMOVE_TEMPS(n$18); [line 20]\n " shape="invhouse"]
22 -> 24 ;
21 [label="21: + \n NULLIFY(&ShouldStop,false); [line 20]\n NULLIFY(&stop,false); [line 20]\n " ]
21 -> 20 ;
20 [label="20: Exit __objc_anonymous_block_MyBlock_array______1 \n " color=yellow style=filled]
19 [label="19: Start __objc_anonymous_block_MyBlock_array______1\nFormals: object:struct objc_object * idx:unsigned long stop:BOOL *\nLocals: ShouldStop:int \n DECLARE_LOCALS(&return,&ShouldStop); [line 15]\n NULLIFY(&idx,false); [line 15]\n NULLIFY(&object,false); [line 15]\n " color=yellow style=filled]
19 -> 22 ;
19 -> 23 ;
18 [label="18: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_MyBlock_array______1); [line 15]\n n$20=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_MyBlock_array______1 ):class __objc_anonymous_block_MyBlock_array______1 *) [line 15]\n *&__objc_anonymous_block_MyBlock_array______1:class __objc_anonymous_block_MyBlock_array______1 =n$20 [line 15]\n *&infer___objc_anonymous_block_MyBlock_array______1:_fn_ (*)=(_fun___objc_anonymous_block_MyBlock_array______1) [line 15]\n REMOVE_TEMPS(n$20); [line 15]\n " shape="box"]
18 -> 17 ;
17 [label="17: DeclStmt \n n$17=_fun_malloc_no_fail(sizeof(signed char ):signed char ) [line 15]\n *&stop:BOOL *=n$17 [line 15]\n REMOVE_TEMPS(n$17); [line 15]\n " shape="box"]
17 -> 16 ;
16 [label="16: BinaryOperatorStmt: Assign \n n$16=*&stop:BOOL * [line 15]\n *n$16:void =0 [line 15]\n REMOVE_TEMPS(n$16); [line 15]\n " shape="box"]
16 -> 5 ;
15 [label="15: DeclStmt \n n$14=*&objects:class NSArray * [line 15]\n n$15=*&idx:unsigned long [line 15]\n n$13=_fun_NSArray_objectAtIndexedSubscript:(n$14:class NSArray *,n$15:unsigned long ) virtual [line 15]\n *&object:struct objc_object *=n$13 [line 15]\n REMOVE_TEMPS(n$13,n$14,n$15); [line 15]\n " shape="box"]
15 -> 14 ;
14 [label="14: Call n$8 \n n$8=*&infer___objc_anonymous_block_MyBlock_array______1:_fn_ (*) [line 15]\n n$9=*&object:struct objc_object * [line 15]\n n$10=*&idx:unsigned long [line 15]\n n$11=*&stop:BOOL * [line 15]\n n$12=n$8(n$9:struct objc_object *,n$10:unsigned long ,n$11:BOOL *) [line 15]\n REMOVE_TEMPS(n$8,n$9,n$10,n$11,n$12); [line 15]\n " shape="box"]
14 -> 11 ;
13 [label="13: Prune (false branch) \n n$7=*n$6:signed char [line 15]\n PRUNE((n$7 == 0), false); [line 15]\n REMOVE_TEMPS(n$6,n$7); [line 15]\n " shape="invhouse"]
13 -> 10 ;
12 [label="12: Prune (true branch) \n n$7=*n$6:signed char [line 15]\n PRUNE((n$7 != 0), true); [line 15]\n REMOVE_TEMPS(n$6,n$7); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="invhouse"]
12 -> 3 ;
11 [label="11: UnaryOperator \n n$6=*&stop:BOOL * [line 15]\n " shape="box"]
11 -> 12 ;
11 -> 13 ;
10 [label="10: + \n " ]
10 -> 6 ;
9 [label="9: Prune (false branch) \n PRUNE(((n$3 < n$4) == 0), false); [line 15]\n REMOVE_TEMPS(n$3,n$4,n$5); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="invhouse"]
9 -> 3 ;
8 [label="8: Prune (true branch) \n PRUNE(((n$3 < n$4) != 0), true); [line 15]\n REMOVE_TEMPS(n$3,n$4,n$5); [line 15]\n " shape="invhouse"]
8 -> 15 ;
7 [label="7: BinaryOperatorStmt: LT \n n$3=*&idx:unsigned long [line 15]\n n$5=*&objects:class NSArray * [line 15]\n n$4=_fun_NSArray_count(n$5:class NSArray *) virtual [line 15]\n " shape="box"]
7 -> 8 ;
7 -> 9 ;
6 [label="6: UnaryOperator \n n$2=*&idx:unsigned long [line 15]\n *&idx:unsigned long =(n$2 + 1) [line 15]\n REMOVE_TEMPS(n$2); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="box"]
6 -> 4 ;
5 [label="5: DeclStmt \n *&idx:unsigned long =0 [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="box"]
5 -> 4 ;
4 [label="4: + \n " ]
4 -> 7 ;
3 [label="3: Call _fun_free \n n$0=*&stop:BOOL * [line 15]\n n$1=_fun_free(n$0:void *) [line 15]\n NULLIFY(&object,true); [line 15]\n NULLIFY(&idx,true); [line 15]\n NULLIFY(&stop,true); [line 15]\n NULLIFY(&objects,true); [line 15]\n REMOVE_TEMPS(n$0,n$1); [line 15]\n NULLIFY(&__objc_anonymous_block_MyBlock_array______1,true); [line 15]\n NULLIFY(&infer___objc_anonymous_block_MyBlock_array______1,true); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit MyBlock_array \n " color=yellow style=filled]
1 [label="1: Start MyBlock_array\nFormals: self:class MyBlock *\nLocals: a:class NSArray * \n DECLARE_LOCALS(&return,&a); [line 12]\n NULLIFY(&a,false); [line 12]\n NULLIFY(&self,false); [line 12]\n " color=yellow style=filled]
1 -> 26 ;
}

@ -0,0 +1,58 @@
#import <Foundation/Foundation.h>
@interface MyBlock : NSObject
@end
@implementation MyBlock
-(void) array {
NSArray *a = [[NSArray alloc] init];
[a enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
int ShouldStop;
/*
... do something here...
*/
if (ShouldStop
) {
*stop= YES;
};
}];
}
-(void) array_trans {
NSArray *a = [[NSArray alloc] init];
NSArray *objects = a;
// The call to the iterator in the above function is translated as:
void (^enumerateObjectsUsingBlock)(id, NSUInteger, BOOL *)= ^(id object, NSUInteger idx, BOOL* stop) {
int ShouldStop;
if (ShouldStop) {
*stop= YES;
};
};
BOOL *stop = malloc(sizeof(BOOL));
*stop = NO;
for (NSUInteger idx=0; idx<objects.count; idx++) {
id object= objects[idx];
enumerateObjectsUsingBlock(object, idx, stop);
if (*stop ==YES) break;
}
free(stop);
}
@end

@ -184,5 +184,24 @@ public class BlockTest {
newDotFile, dotFileEqualTo(block_dotty));
}
@Test
public void whenCaptureRunOnBlockit_exampleThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
String block_src =
"infer/tests/codetoanalyze/objc/frontend/block/block-it.m";
String block_dotty =
"infer/tests/codetoanalyze/objc/frontend/block/block-it.dot";
ImmutableList<String> inferCmd =
InferRunner.createiOSInferCommandFrontend(folder, block_src);
File newDotFile = InferRunner.runInferFrontend(inferCmd);
assertThat(
"In the capture of " + block_src +
" the dotty files should be the same.",
newDotFile, dotFileEqualTo(block_dotty));
}
}

Loading…
Cancel
Save