@@ -41,10 +41,11 @@ use move_binary_format::{
41
41
binary_views:: BinaryIndexedView ,
42
42
file_format:: {
43
43
AddressIdentifierIndex , Bytecode , CodeOffset , Constant as VMConstant , ConstantPoolIndex ,
44
- FunctionDefinitionIndex , FunctionHandleIndex , SignatureIndex , SignatureToken ,
45
- StructDefinitionIndex , StructFieldInformation , StructHandleIndex , Visibility ,
44
+ FunctionDefinitionIndex , FunctionHandleIndex , FunctionInstantiation , SignatureIndex ,
45
+ SignatureToken , StructDefinitionIndex , StructFieldInformation , StructHandleIndex ,
46
+ Visibility ,
46
47
} ,
47
- normalized:: Type as MType ,
48
+ normalized:: { FunctionRef , Type as MType } ,
48
49
views:: {
49
50
FieldDefinitionView , FunctionDefinitionView , FunctionHandleView , SignatureTokenView ,
50
51
StructDefinitionView , StructHandleView ,
@@ -87,6 +88,14 @@ pub const SCRIPT_BYTECODE_FUN_NAME: &str = "<SELF>";
87
88
/// A prefix used for structs which are backing specification ("ghost") memory.
88
89
pub const GHOST_MEMORY_PREFIX : & str = "Ghost$" ;
89
90
91
+ const SUI_FRAMEWORK_ADDRESS : AccountAddress = address_from_single_byte ( 2 ) ;
92
+
93
+ const fn address_from_single_byte ( b : u8 ) -> AccountAddress {
94
+ let mut addr = [ 0u8 ; AccountAddress :: LENGTH ] ;
95
+ addr[ AccountAddress :: LENGTH - 1 ] = b;
96
+ AccountAddress :: new ( addr)
97
+ }
98
+
90
99
// =================================================================================================
91
100
/// # Locations
92
101
@@ -160,6 +169,13 @@ impl Default for Loc {
160
169
}
161
170
}
162
171
172
+ /// Return true if `f` is a Sui framework function declared in `module` with a name in `names`
173
+ fn is_framework_function ( f : & FunctionRef , module : & str , names : Vec < & str > ) -> bool {
174
+ * f. module_id . address ( ) == SUI_FRAMEWORK_ADDRESS
175
+ && f. module_id . name ( ) . to_string ( ) == module
176
+ && names. contains ( & f. function_ident . as_str ( ) )
177
+ }
178
+
163
179
/// Alias for the Loc variant of MoveIR. This uses a `&static str` instead of `FileId` for the
164
180
/// file name.
165
181
pub type MoveIrLoc = move_ir_types:: location:: Loc ;
@@ -2193,11 +2209,93 @@ impl<'env> ModuleEnv<'env> {
2193
2209
self . data . struct_data . len ( )
2194
2210
}
2195
2211
2196
- /// Returns iterator over structs in this module.
2212
+ /// Returns an iterator over structs in this module.
2197
2213
pub fn get_structs ( & ' env self ) -> impl Iterator < Item = StructEnv < ' env > > {
2198
2214
self . clone ( ) . into_structs ( )
2199
2215
}
2200
2216
2217
+ /// Returns an iterator over all object types declared by this module
2218
+ pub fn get_objects ( & ' env self ) -> impl Iterator < Item = StructEnv < ' env > > {
2219
+ self . clone ( )
2220
+ . into_structs ( )
2221
+ . filter ( |s| s. get_abilities ( ) . has_key ( ) )
2222
+ }
2223
+
2224
+ /// Returns the object types that are shared by code in this module
2225
+ /// If `transitive` is false, only return objects directly shared by functions declared in this module
2226
+ /// If `transitive` is true, return objects shared by both functions declared in this module and by transitive callees
2227
+ /// Note that this can include both types declared inside this module (common case) and types declared outside
2228
+ /// Note that objects with `store` can be shared by modules that depend on this one (e.g., by returning the object and subsequently calling `public_share_object`)
2229
+ pub fn get_shared_objects ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
2230
+ let mut shared = BTreeSet :: new ( ) ;
2231
+ for f in self . get_functions ( ) {
2232
+ shared. extend ( f. get_shared_objects ( transitive) ) ;
2233
+ }
2234
+ shared
2235
+ }
2236
+
2237
+ /// Returns the object types that are frozen by this module
2238
+ /// If `transitive` is false, only return objects directly transferred by functions declared in this module
2239
+ /// If `transitive` is true, return objects transferred by both functions declared in this module and by transitive callees
2240
+ /// Note that this function can return both types declared inside this module (common case) and types declared outside
2241
+ /// Note that objects with `store` can be transferred by modules that depend on this one (e.g., by returning the object and subsequently calling `public_transfer`),
2242
+ /// or transferred by a command in a programmable transaction block
2243
+ pub fn get_transferred_objects ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
2244
+ let mut transferred = BTreeSet :: new ( ) ;
2245
+ for f in self . get_functions ( ) {
2246
+ transferred. extend ( f. get_transferred_objects ( transitive) )
2247
+ }
2248
+ transferred
2249
+ }
2250
+
2251
+ /// Returns the object types that are frozen by this module
2252
+ /// If `transitive` is false, only return objects directly frozen by functions declared in this module
2253
+ /// If `transitive` is true, return objects frozen by both functions declared in this module and by transitive callees
2254
+ /// Note that this function can return both types declared inside this module (common case) and types declared outside
2255
+ /// Note that objects with `store` can be frozen by modules that depend on this one (e.g., by returning the object and subsequently calling `public_freeze`)
2256
+ pub fn get_frozen_objects ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
2257
+ let mut frozen = BTreeSet :: new ( ) ;
2258
+ for f in self . get_functions ( ) {
2259
+ frozen. extend ( f. get_frozen_objects ( transitive) )
2260
+ }
2261
+ frozen
2262
+ }
2263
+
2264
+ /// Returns the event types that are emitted by this module
2265
+ /// If `transitive` is false, only return events directly emitted by functions declared in this module
2266
+ /// If `transitive` is true, return events emitted by both functions declared in this module and by transitive callees
2267
+ /// Note that this function can return both event types declared inside this module (common case) and event types declared outside
2268
+ pub fn get_events ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
2269
+ let mut frozen = BTreeSet :: new ( ) ;
2270
+ for f in self . get_functions ( ) {
2271
+ frozen. extend ( f. get_frozen_objects ( transitive) )
2272
+ }
2273
+ frozen
2274
+ }
2275
+
2276
+ /// Returns the objects types that are returned by externally callable (`public`, `entry`, and `friend`) functions in this module
2277
+ /// Returned objects with `store` can be transferred, shared, frozen, or wrapped by a different module
2278
+ /// Note that this function returns object types both with and without `store`
2279
+ pub fn get_externally_returned_objects ( & ' env self ) -> BTreeSet < Type > {
2280
+ let mut returned = BTreeSet :: new ( ) ;
2281
+ for f in self . get_functions ( ) {
2282
+ if !f. is_exposed ( ) {
2283
+ continue ;
2284
+ }
2285
+ // Objects returned by a public function can be transferred, shared, frozen, or wrapped
2286
+ // by a different module or (in the case of transfer) by a command in a programmable transaction block.
2287
+ for f in f. get_return_types ( ) {
2288
+ if let Type :: Struct ( mid, sid, _) = f {
2289
+ let struct_env = self . env . get_module ( mid) . into_struct ( sid) ;
2290
+ if struct_env. get_abilities ( ) . has_key ( ) {
2291
+ returned. insert ( f) ;
2292
+ }
2293
+ }
2294
+ }
2295
+ }
2296
+ returned
2297
+ }
2298
+
2201
2299
/// Returns iterator over structs in this module.
2202
2300
pub fn into_structs ( self ) -> impl Iterator < Item = StructEnv < ' env > > {
2203
2301
self . data . struct_data . values ( ) . map ( move |data| StructEnv {
@@ -3735,6 +3833,142 @@ impl<'env> FunctionEnv<'env> {
3735
3833
type_param_names : Some ( type_param_names) ,
3736
3834
}
3737
3835
}
3836
+
3837
+ /// Returns the object types that may be shared by this function
3838
+ /// If `transitive` is false, only return objects directly shared by this function
3839
+ /// If `transitive` is true, return objects shared by both this function and its transitive callees
3840
+ pub fn get_shared_objects ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
3841
+ let mut shared = BTreeSet :: new ( ) ;
3842
+ if transitive {
3843
+ let callees = self . get_transitive_closure_of_called_functions ( ) ;
3844
+ for callee in callees {
3845
+ let fenv = self . module_env . env . get_function ( callee) ;
3846
+ shared. extend ( fenv. get_shared_objects ( false ) ) ;
3847
+ }
3848
+ } else {
3849
+ let module = & self . module_env . data . module ;
3850
+ for b in self . get_bytecode ( ) {
3851
+ if let Bytecode :: CallGeneric ( fi_idx) = b {
3852
+ let FunctionInstantiation {
3853
+ handle,
3854
+ type_parameters,
3855
+ } = module. function_instantiation_at ( * fi_idx) ;
3856
+ let f_ref = FunctionRef :: from_idx ( module, handle) ;
3857
+ if is_framework_function (
3858
+ & f_ref,
3859
+ "transfer" ,
3860
+ vec ! [ "share_object" , "public_share_object" ] ,
3861
+ ) {
3862
+ let type_params = module. signature_at ( * type_parameters) ;
3863
+ shared. insert ( self . module_env . globalize_signature ( & type_params. 0 [ 0 ] ) ) ;
3864
+ }
3865
+ }
3866
+ }
3867
+ }
3868
+
3869
+ shared
3870
+ }
3871
+
3872
+ /// Returns the object types that may be transferred by this function
3873
+ /// If `transitive` is false, only objects directly transferred by this function
3874
+ /// If `transitive` is true, return objects transferred by both this function and its transitive callees
3875
+ pub fn get_transferred_objects ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
3876
+ let mut transferred = BTreeSet :: new ( ) ;
3877
+ if transitive {
3878
+ let callees = self . get_transitive_closure_of_called_functions ( ) ;
3879
+ for callee in callees {
3880
+ let fenv = self . module_env . env . get_function ( callee) ;
3881
+ transferred. extend ( fenv. get_shared_objects ( false ) ) ;
3882
+ }
3883
+ } else {
3884
+ let module = & self . module_env . data . module ;
3885
+ for b in self . get_bytecode ( ) {
3886
+ if let Bytecode :: CallGeneric ( fi_idx) = b {
3887
+ let FunctionInstantiation {
3888
+ handle,
3889
+ type_parameters,
3890
+ } = module. function_instantiation_at ( * fi_idx) ;
3891
+ let f_ref = FunctionRef :: from_idx ( module, handle) ;
3892
+ if is_framework_function (
3893
+ & f_ref,
3894
+ "transfer" ,
3895
+ vec ! [ "transfer" , "public_transfer" ] ,
3896
+ ) {
3897
+ let type_params = module. signature_at ( * type_parameters) ;
3898
+ transferred. insert ( self . module_env . globalize_signature ( & type_params. 0 [ 0 ] ) ) ;
3899
+ }
3900
+ }
3901
+ }
3902
+ }
3903
+
3904
+ transferred
3905
+ }
3906
+
3907
+ /// Returns the object types that may be frozen by this function
3908
+ /// If `transitive` is false, only return objects directly frozen by this function
3909
+ /// If `transitive` is true, return objects frozen by both this function and its transitive callees
3910
+ pub fn get_frozen_objects ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
3911
+ let mut frozen = BTreeSet :: new ( ) ;
3912
+ if transitive {
3913
+ let callees = self . get_transitive_closure_of_called_functions ( ) ;
3914
+ for callee in callees {
3915
+ let fenv = self . module_env . env . get_function ( callee) ;
3916
+ frozen. extend ( fenv. get_shared_objects ( false ) ) ;
3917
+ }
3918
+ } else {
3919
+ let module = & self . module_env . data . module ;
3920
+ for b in self . get_bytecode ( ) {
3921
+ if let Bytecode :: CallGeneric ( fi_idx) = b {
3922
+ let FunctionInstantiation {
3923
+ handle,
3924
+ type_parameters,
3925
+ } = module. function_instantiation_at ( * fi_idx) ;
3926
+ let f_ref = FunctionRef :: from_idx ( module, handle) ;
3927
+ if is_framework_function (
3928
+ & f_ref,
3929
+ "transfer" ,
3930
+ vec ! [ "freeze_object" , "public_freeze_object" ] ,
3931
+ ) {
3932
+ let type_params = module. signature_at ( * type_parameters) ;
3933
+ frozen. insert ( self . module_env . globalize_signature ( & type_params. 0 [ 0 ] ) ) ;
3934
+ }
3935
+ }
3936
+ }
3937
+ }
3938
+
3939
+ frozen
3940
+ }
3941
+
3942
+ /// Returns the event types that may be emitted by this function
3943
+ /// If `transitive` is false, only return events directly emitted by this function
3944
+ /// If `transitive` is true, return events emitted by both this function and its transitive callees
3945
+ pub fn get_events ( & ' env self , transitive : bool ) -> BTreeSet < Type > {
3946
+ let mut events = BTreeSet :: new ( ) ;
3947
+ if transitive {
3948
+ let callees = self . get_transitive_closure_of_called_functions ( ) ;
3949
+ for callee in callees {
3950
+ let fenv = self . module_env . env . get_function ( callee) ;
3951
+ events. extend ( fenv. get_events ( false ) ) ;
3952
+ }
3953
+ } else {
3954
+ let module = & self . module_env . data . module ;
3955
+ for b in self . get_bytecode ( ) {
3956
+ if let Bytecode :: CallGeneric ( fi_idx) = b {
3957
+ let FunctionInstantiation {
3958
+ handle,
3959
+ type_parameters,
3960
+ } = module. function_instantiation_at ( * fi_idx) ;
3961
+ let f_ref = FunctionRef :: from_idx ( module, handle) ;
3962
+ if is_framework_function ( & f_ref, "event" , vec ! [ "emit" ] ) {
3963
+ let type_params = module. signature_at ( * type_parameters) ;
3964
+ events. insert ( self . module_env . globalize_signature ( & type_params. 0 [ 0 ] ) ) ;
3965
+ }
3966
+ }
3967
+ }
3968
+ }
3969
+
3970
+ events
3971
+ }
3738
3972
}
3739
3973
3740
3974
// =================================================================================================
0 commit comments