@@ -41,10 +41,11 @@ use move_binary_format::{
4141 binary_views:: BinaryIndexedView ,
4242 file_format:: {
4343 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 ,
4647 } ,
47- normalized:: Type as MType ,
48+ normalized:: { FunctionRef , Type as MType } ,
4849 views:: {
4950 FieldDefinitionView , FunctionDefinitionView , FunctionHandleView , SignatureTokenView ,
5051 StructDefinitionView , StructHandleView ,
@@ -87,6 +88,14 @@ pub const SCRIPT_BYTECODE_FUN_NAME: &str = "<SELF>";
8788/// A prefix used for structs which are backing specification ("ghost") memory.
8889pub const GHOST_MEMORY_PREFIX : & str = "Ghost$" ;
8990
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+
9099// =================================================================================================
91100/// # Locations
92101
@@ -160,6 +169,13 @@ impl Default for Loc {
160169 }
161170}
162171
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+
163179/// Alias for the Loc variant of MoveIR. This uses a `&static str` instead of `FileId` for the
164180/// file name.
165181pub type MoveIrLoc = move_ir_types:: location:: Loc ;
@@ -2193,11 +2209,93 @@ impl<'env> ModuleEnv<'env> {
21932209 self . data . struct_data . len ( )
21942210 }
21952211
2196- /// Returns iterator over structs in this module.
2212+ /// Returns an iterator over structs in this module.
21972213 pub fn get_structs ( & ' env self ) -> impl Iterator < Item = StructEnv < ' env > > {
21982214 self . clone ( ) . into_structs ( )
21992215 }
22002216
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+
22012299 /// Returns iterator over structs in this module.
22022300 pub fn into_structs ( self ) -> impl Iterator < Item = StructEnv < ' env > > {
22032301 self . data . struct_data . values ( ) . map ( move |data| StructEnv {
@@ -3735,6 +3833,142 @@ impl<'env> FunctionEnv<'env> {
37353833 type_param_names : Some ( type_param_names) ,
37363834 }
37373835 }
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+ }
37383972}
37393973
37403974// =================================================================================================
0 commit comments