[frontend] ObjC setter/getter for C struct field

Summary: This diff copies each field values inside setter/getter of ObjC.

Reviewed By: ezgicicek

Differential Revision: D27940521

fbshipit-source-id: 9977cae75
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent f43d7aa5fb
commit 851fb3267b

@ -17,53 +17,64 @@ let get_load_self_instr location (self, self_typ) fieldname =
(field_exp, load_self_instr)
let objc_getter proc_desc location self_with_typ (fieldname, field_typ, _) =
let objc_getter tenv proc_desc location self_with_typ (fieldname, field_typ, _) =
let field_exp, load_self_instr = get_load_self_instr location self_with_typ fieldname in
let id_field = Ident.create_fresh Ident.knormal in
let store_instrs =
let id_field = Ident.create_fresh Ident.knormal in
let load_field_instr =
Sil.Load {id= id_field; e= field_exp; root_typ= field_typ; typ= field_typ; loc= location}
in
let exp_var = Exp.Lvar (Procdesc.get_ret_var proc_desc) in
let return_exp =
Sil.Store
{e1= exp_var; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location}
in
[load_field_instr; return_exp]
match field_typ with
| {Typ.desc= Tstruct (CStruct _ as struct_name)} ->
let ret_param = Exp.Lvar (Pvar.get_ret_param_pvar (Procdesc.get_proc_name proc_desc)) in
Sil.Load {id= id_field; e= ret_param; root_typ= field_typ; typ= field_typ; loc= location}
:: CStructCopy.struct_copy tenv location (Exp.Var id_field) field_exp ~typ:field_typ
~struct_name
| _ ->
let load_field_instr =
Sil.Load {id= id_field; e= field_exp; root_typ= field_typ; typ= field_typ; loc= location}
in
let exp_var = Exp.Lvar (Procdesc.get_ret_var proc_desc) in
let return_exp =
Sil.Store
{e1= exp_var; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location}
in
[load_field_instr; return_exp]
in
load_self_instr :: store_instrs
let objc_setter location self_with_typ (var, var_typ) (fieldname, field_typ, _) =
let objc_setter tenv location self_with_typ (var, var_typ) (fieldname, field_typ, _) =
let field_exp, load_self_instr = get_load_self_instr location self_with_typ fieldname in
let store_instrs =
let id_field = Ident.create_fresh Ident.knormal in
let load_var_instr =
Sil.Load {id= id_field; e= Lvar var; root_typ= var_typ; typ= var_typ; loc= location}
in
let store_exp =
Sil.Store
{e1= field_exp; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location}
in
[load_var_instr; store_exp]
match field_typ with
| {Typ.desc= Tstruct (CStruct _ as struct_name)} ->
CStructCopy.struct_copy tenv location field_exp (Exp.Lvar var) ~typ:field_typ ~struct_name
| _ ->
let id_field = Ident.create_fresh Ident.knormal in
let load_var_instr =
Sil.Load {id= id_field; e= Lvar var; root_typ= var_typ; typ= var_typ; loc= location}
in
let store_exp =
Sil.Store
{e1= field_exp; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location}
in
[load_var_instr; store_exp]
in
load_self_instr :: store_instrs
let process_getter_setter proc_name proc_desc =
let process_getter_setter tenv proc_name proc_desc =
let location = Procdesc.get_loc proc_desc in
let formals = Procdesc.get_formals proc_desc in
let attributes = Procdesc.get_attributes proc_desc in
Ident.NameGenerator.reset () ;
let getter_setter_instrs =
match (attributes.ProcAttributes.objc_accessor, formals) with
| Some (Objc_getter field), [(self, self_typ)] ->
| Some (Objc_getter field), (self, self_typ) :: _ ->
let self_var = Pvar.mk self proc_name in
objc_getter proc_desc location (self_var, self_typ) field
objc_getter tenv proc_desc location (self_var, self_typ) field
| Some (Objc_setter field), [(self, self_typ); (var_name, var_typ)] ->
let self_var = Pvar.mk self proc_name in
let var = Pvar.mk var_name proc_name in
objc_setter location (self_var, self_typ) (var, var_typ) field
objc_setter tenv location (self_var, self_typ) (var, var_typ) field
| _ ->
[]
in
@ -83,4 +94,4 @@ let process_getter_setter proc_name proc_desc =
Procdesc.node_set_succs proc_desc getter_setter_node ~normal:[exit_node] ~exn:[] )
let process cfg = Procname.Hash.iter process_getter_setter cfg
let process cfg tenv = Procname.Hash.iter (process_getter_setter tenv) cfg

@ -7,7 +7,7 @@
open! IStd
val process : Cfg.t -> unit
val process : Cfg.t -> Tenv.t -> unit
(** In Objective-C when properties are created in the interface of a class, the compiler creates
automatically the instance variable for it and also the getter and setter in the implementation
of the class. In the frontend we collect the information about which method is the implicit

@ -51,7 +51,7 @@ let do_source_file (translation_unit_context : CFrontend_config.translation_unit
"@\n Start building call/cfg graph for '%a'....@\n" SourceFile.pp source_file ;
let cfg = compute_icfg translation_unit_context tenv ast in
CAddImplicitDeallocImpl.process cfg tenv ;
CAddImplicitGettersSetters.process cfg ;
CAddImplicitGettersSetters.process cfg tenv ;
CCallSpecializedWithClosures.process cfg ;
L.(debug Capture Verbose) "@\n End building call/cfg graph for '%a'.@\n" SourceFile.pp source_file ;
NullabilityPreanalysis.analysis cfg tenv ;

@ -48,7 +48,8 @@ type t =
(* A method is a getter if it has a link to a property and *)
(* it has 0 arguments *)
let is_getter {pointer_to_property_opt; params} =
Option.is_some pointer_to_property_opt && Int.equal (List.length params) 0
Option.is_some pointer_to_property_opt
&& match params with [] -> true | [{name}] -> Mangled.is_return_param name | _ -> false
(* A method is a setter if it has a link to a property and *)

@ -7,8 +7,14 @@
#import <Foundation/NSObject.h>
struct my_struct {
int x;
int y;
};
@interface A : NSObject
@property int x;
@property(nonatomic, readwrite) struct my_struct s;
@end
@implementation A
@ -17,4 +23,9 @@
return target.x;
}
+ (int)getMyStructField:(A*)target my_struct:(struct my_struct)my_struct {
target.s = my_struct;
return target.s.x;
}
@end

@ -1,5 +1,24 @@
/* @generated */
digraph cfg {
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_1" [label="1: Start A.getMyStructField:my_struct:\nFormals: target:A* my_struct:my_struct\nLocals: 0$?%__sil_tmp__temp_return_n$4:my_struct \n " color=yellow style=filled]
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_1" -> "getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_5" ;
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_2" [label="2: Exit A.getMyStructField:my_struct: \n " color=yellow style=filled]
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_3" [label="3: Return Stmt \n n$2=*&target:A* [line 28, column 10]\n n$5=_fun_A.s(n$2:A*,&0$?%__sil_tmp__temp_return_n$4:my_struct*) assign_last [line 28, column 17]\n n$6=*&0$?%__sil_tmp__temp_return_n$4.x:int [line 28, column 10]\n " shape="box"]
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_3" -> "getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_4" ;
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_4" [label="4: Return Stmt \n *&return:int=n$6 [line 28, column 3]\n " shape="box"]
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_4" -> "getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_2" ;
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_5" [label="5: Message Call: setS: \n n$8=*&target:A* [line 27, column 3]\n n$7=*&my_struct:my_struct [line 27, column 14]\n n$9=_fun_A.setS:(n$8:A*,n$7:my_struct) [line 27, column 10]\n " shape="box"]
"getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_5" -> "getMyStructField:my_struct:#A(class A)#class.35da25720e80922866aa41dc70b313cb_3" ;
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_1" [label="1: Start A.addTarget:\nFormals: self:A* target:A*\nLocals: \n " color=yellow style=filled]
@ -7,11 +26,11 @@ digraph cfg {
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_2" [label="2: Exit A.addTarget: \n " color=yellow style=filled]
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_3" [label="3: Return Stmt \n n$0=*&target:A* [line 17, column 10]\n n$1=_fun_A.x(n$0:A*) [line 17, column 17]\n " shape="box"]
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_3" [label="3: Return Stmt \n n$0=*&target:A* [line 23, column 10]\n n$1=_fun_A.x(n$0:A*) [line 23, column 17]\n " shape="box"]
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_3" -> "addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_4" ;
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_4" [label="4: Return Stmt \n *&return:int=n$1 [line 17, column 3]\n " shape="box"]
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_4" [label="4: Return Stmt \n *&return:int=n$1 [line 23, column 3]\n " shape="box"]
"addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_4" -> "addTarget:#A(class A)#instance.ca26ddd02ac11fb266531b38b6edef27_2" ;
@ -26,6 +45,28 @@ digraph cfg {
"dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_3" -> "dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_2" ;
"s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_1" [label="1: Start A.s\nFormals: self:A* __return_param:my_struct*\nLocals: \n " color=yellow style=filled]
"s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_1" -> "s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_3" ;
"s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_2" [label="2: Exit A.s \n " color=yellow style=filled]
"s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_3" [label="3: BinaryOperatorStmt: Node \n n$0=*&self:A* [line 17, column 50]\n n$1=*&__return_param:my_struct [line 17, column 50]\n n$2=*n$0._s.x:int [line 17, column 50]\n *n$1.x:int=n$2 [line 17, column 50]\n n$3=*n$0._s.y:int [line 17, column 50]\n *n$1.y:int=n$3 [line 17, column 50]\n " shape="box"]
"s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_3" -> "s#A(struct my_struct)#instance.8b615eca1cde58c02b016bbbf517c211_2" ;
"setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_1" [label="1: Start A.setS:\nFormals: self:A* s:my_struct\nLocals: \n " color=yellow style=filled]
"setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_1" -> "setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_3" ;
"setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_2" [label="2: Exit A.setS: \n " color=yellow style=filled]
"setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_3" [label="3: BinaryOperatorStmt: Node \n n$0=*&self:A* [line 17, column 50]\n n$1=*&s.x:int [line 17, column 50]\n *n$0._s.x:int=n$1 [line 17, column 50]\n n$2=*&s.y:int [line 17, column 50]\n *n$0._s.y:int=n$2 [line 17, column 50]\n " shape="box"]
"setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_3" -> "setS:#A#instance.190e00a9f8a69bd26b1a4e2b795d840c_2" ;
"setX:#A#instance.00c5402542b9aade8ca8191be56dcd87_1" [label="1: Start A.setX:\nFormals: self:A* x:int\nLocals: \n " color=yellow style=filled]
@ -33,7 +74,7 @@ digraph cfg {
"setX:#A#instance.00c5402542b9aade8ca8191be56dcd87_2" [label="2: Exit A.setX: \n " color=yellow style=filled]
"setX:#A#instance.00c5402542b9aade8ca8191be56dcd87_3" [label="3: BinaryOperatorStmt: Node \n n$0=*&self:A* [line 11, column 15]\n n$1=*&x:int [line 11, column 15]\n *n$0._x:int=n$1 [line 11, column 15]\n " shape="box"]
"setX:#A#instance.00c5402542b9aade8ca8191be56dcd87_3" [label="3: BinaryOperatorStmt: Node \n n$0=*&self:A* [line 16, column 15]\n n$1=*&x:int [line 16, column 15]\n *n$0._x:int=n$1 [line 16, column 15]\n " shape="box"]
"setX:#A#instance.00c5402542b9aade8ca8191be56dcd87_3" -> "setX:#A#instance.00c5402542b9aade8ca8191be56dcd87_2" ;
@ -44,7 +85,7 @@ digraph cfg {
"x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_2" [label="2: Exit A.x \n " color=yellow style=filled]
"x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_3" [label="3: BinaryOperatorStmt: Node \n n$0=*&self:A* [line 11, column 15]\n n$1=*n$0._x:int [line 11, column 15]\n *&return:int=n$1 [line 11, column 15]\n " shape="box"]
"x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_3" [label="3: BinaryOperatorStmt: Node \n n$0=*&self:A* [line 16, column 15]\n n$1=*n$0._x:int [line 16, column 15]\n *&return:int=n$1 [line 16, column 15]\n " shape="box"]
"x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_3" -> "x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_2" ;

@ -6,17 +6,18 @@
*/
#import <Foundation/Foundation.h>
struct my_struct {
int x;
int y;
};
@interface Uninit : NSObject
@property(nonatomic, assign) int obj_field;
@property(nonatomic, readwrite) struct my_struct s;
@end
struct my_struct {
int x;
int y;
};
@implementation Uninit
- (void)capture_in_closure_ok {
@ -115,4 +116,25 @@ dispatch_queue_t queue;
return x;
}
+ (int)getter_c_struct:(Uninit*)obj {
struct my_struct s = obj.s; // getter is called
return s.x;
}
- (int)call_getter_c_struct_ok {
Uninit* obj = [Uninit new];
struct my_struct s;
s.x = 1;
s.y = 2;
obj.s = s; // setter is called
return [Uninit getter_c_struct:obj];
}
/* FN due to the frontend is incorrect when passing C struct value as a function
paraemeter when calling C struct setter. */
+ (void)call_setter_c_struct_bad_FN:(Uninit*)obj {
struct my_struct s;
obj.s = s; // setter is called
}
@end

Loading…
Cancel
Save