[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) (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 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 store_instrs =
let id_field = Ident.create_fresh Ident.knormal in match field_typ with
let load_field_instr = | {Typ.desc= Tstruct (CStruct _ as struct_name)} ->
Sil.Load {id= id_field; e= field_exp; root_typ= field_typ; typ= field_typ; loc= location} let ret_param = Exp.Lvar (Pvar.get_ret_param_pvar (Procdesc.get_proc_name proc_desc)) in
in Sil.Load {id= id_field; e= ret_param; root_typ= field_typ; typ= field_typ; loc= location}
let exp_var = Exp.Lvar (Procdesc.get_ret_var proc_desc) in :: CStructCopy.struct_copy tenv location (Exp.Var id_field) field_exp ~typ:field_typ
let return_exp = ~struct_name
Sil.Store | _ ->
{e1= exp_var; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location} let load_field_instr =
in Sil.Load {id= id_field; e= field_exp; root_typ= field_typ; typ= field_typ; loc= location}
[load_field_instr; return_exp] 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 in
load_self_instr :: store_instrs 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 field_exp, load_self_instr = get_load_self_instr location self_with_typ fieldname in
let store_instrs = let store_instrs =
let id_field = Ident.create_fresh Ident.knormal in match field_typ with
let load_var_instr = | {Typ.desc= Tstruct (CStruct _ as struct_name)} ->
Sil.Load {id= id_field; e= Lvar var; root_typ= var_typ; typ= var_typ; loc= location} CStructCopy.struct_copy tenv location field_exp (Exp.Lvar var) ~typ:field_typ ~struct_name
in | _ ->
let store_exp = let id_field = Ident.create_fresh Ident.knormal in
Sil.Store let load_var_instr =
{e1= field_exp; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location} Sil.Load {id= id_field; e= Lvar var; root_typ= var_typ; typ= var_typ; loc= location}
in in
[load_var_instr; store_exp] 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 in
load_self_instr :: store_instrs 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 location = Procdesc.get_loc proc_desc in
let formals = Procdesc.get_formals proc_desc in let formals = Procdesc.get_formals proc_desc in
let attributes = Procdesc.get_attributes proc_desc in let attributes = Procdesc.get_attributes proc_desc in
Ident.NameGenerator.reset () ; Ident.NameGenerator.reset () ;
let getter_setter_instrs = let getter_setter_instrs =
match (attributes.ProcAttributes.objc_accessor, formals) with 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 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)] -> | Some (Objc_setter field), [(self, self_typ); (var_name, var_typ)] ->
let self_var = Pvar.mk self proc_name in let self_var = Pvar.mk self proc_name in
let var = Pvar.mk var_name 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 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:[] ) 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 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 (** 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 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 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 ; "@\n Start building call/cfg graph for '%a'....@\n" SourceFile.pp source_file ;
let cfg = compute_icfg translation_unit_context tenv ast in let cfg = compute_icfg translation_unit_context tenv ast in
CAddImplicitDeallocImpl.process cfg tenv ; CAddImplicitDeallocImpl.process cfg tenv ;
CAddImplicitGettersSetters.process cfg ; CAddImplicitGettersSetters.process cfg tenv ;
CCallSpecializedWithClosures.process cfg ; CCallSpecializedWithClosures.process cfg ;
L.(debug Capture Verbose) "@\n End building call/cfg graph for '%a'.@\n" SourceFile.pp source_file ; L.(debug Capture Verbose) "@\n End building call/cfg graph for '%a'.@\n" SourceFile.pp source_file ;
NullabilityPreanalysis.analysis cfg tenv ; NullabilityPreanalysis.analysis cfg tenv ;

@ -48,7 +48,8 @@ type t =
(* A method is a getter if it has a link to a property and *) (* A method is a getter if it has a link to a property and *)
(* it has 0 arguments *) (* it has 0 arguments *)
let is_getter {pointer_to_property_opt; params} = 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 *) (* A method is a setter if it has a link to a property and *)

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

@ -1,5 +1,24 @@
/* @generated */ /* @generated */
digraph cfg { 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] "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_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_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" ; "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" ; "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] "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_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" ; "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_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" ; "x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_3" -> "x#A#instance.37ea1b3cd5342ae67c7383da2227f91f_2" ;

@ -6,17 +6,18 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
struct my_struct {
int x;
int y;
};
@interface Uninit : NSObject @interface Uninit : NSObject
@property(nonatomic, assign) int obj_field; @property(nonatomic, assign) int obj_field;
@property(nonatomic, readwrite) struct my_struct s;
@end @end
struct my_struct {
int x;
int y;
};
@implementation Uninit @implementation Uninit
- (void)capture_in_closure_ok { - (void)capture_in_closure_ok {
@ -115,4 +116,25 @@ dispatch_queue_t queue;
return x; 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 @end

Loading…
Cancel
Save