Better handling of state variable signatures

especially contract-type variables and functions that return them
pull/1802/head
webthethird 2 years ago
parent c3f42c62e6
commit 36e1ac1e01
  1. 51
      slither/utils/code_generation.py

@ -1,19 +1,25 @@
# Functions for generating Solidity code # Functions for generating Solidity code
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from slither.utils.type import convert_type_for_solidity_signature_to_string from slither.utils.type import (
from slither.core.solidity_types.user_defined_type import UserDefinedType convert_type_for_solidity_signature_to_string,
from slither.core.declarations import Structure, Enum export_nested_types_from_variable,
export_return_type_from_variable,
)
from slither.core.solidity_types import UserDefinedType, MappingType, ArrayType
from slither.core.declarations import Structure, Enum, Contract
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations import FunctionContract, Contract, CustomErrorContract from slither.core.declarations import FunctionContract, CustomErrorContract
from slither.core.variables import StateVariable
def generate_interface(contract: "Contract", unroll_structs: bool = True) -> str: def generate_interface(contract: "Contract", unroll_structs: bool = True) -> str:
""" """
Generates code for a Solidity interface to the contract. Generates code for a Solidity interface to the contract.
Args: Args:
contract: A Contract object contract: A Contract object.
unroll_structs: Specifies whether to use structures' underlying types instead of the user-defined type.
Returns: Returns:
A string with the code for an interface, with function stubs for all public or external functions and A string with the code for an interface, with function stubs for all public or external functions and
@ -30,7 +36,7 @@ def generate_interface(contract: "Contract", unroll_structs: bool = True) -> str
for struct in contract.structures: for struct in contract.structures:
interface += generate_struct_interface_str(struct) interface += generate_struct_interface_str(struct)
for var in contract.state_variables_entry_points: for var in contract.state_variables_entry_points:
interface += f" function {var.signature_str.replace('returns', 'external returns ')};\n" interface += generate_interface_variable_signature(var, unroll_structs)
for func in contract.functions_entry_points: for func in contract.functions_entry_points:
if func.is_constructor or func.is_fallback or func.is_receive: if func.is_constructor or func.is_fallback or func.is_receive:
continue continue
@ -41,6 +47,35 @@ def generate_interface(contract: "Contract", unroll_structs: bool = True) -> str
return interface return interface
def generate_interface_variable_signature(
var: "StateVariable", unroll_structs: bool = True
) -> Optional[str]:
if unroll_structs:
params = [
convert_type_for_solidity_signature_to_string(x).replace("(", "").replace(")", "")
for x in export_nested_types_from_variable(var)
]
returns = [
convert_type_for_solidity_signature_to_string(x).replace("(", "").replace(")", "")
for x in export_return_type_from_variable(var)
]
else:
_, params, _ = var.signature
returns = []
_type = var.type
while isinstance(_type, MappingType):
_type = _type.type_to
while isinstance(_type, (ArrayType, UserDefinedType)):
_type = _type.type
ret = str(_type)
if isinstance(_type, Structure):
ret += " memory"
elif isinstance(_type, Contract):
ret = "address"
returns.append(ret)
return f" function {var.name}({','.join(params)}) external returns ({', '.join(returns)});\n"
def generate_interface_function_signature( def generate_interface_function_signature(
func: "FunctionContract", unroll_structs: bool = True func: "FunctionContract", unroll_structs: bool = True
) -> Optional[str]: ) -> Optional[str]:
@ -72,6 +107,8 @@ def generate_interface_function_signature(
if unroll_structs if unroll_structs
else f"{str(ret.type.type)} memory" else f"{str(ret.type.type)} memory"
if isinstance(ret.type, UserDefinedType) and isinstance(ret.type.type, (Structure, Enum)) if isinstance(ret.type, UserDefinedType) and isinstance(ret.type.type, (Structure, Enum))
else "address"
if isinstance(ret.type, UserDefinedType) and isinstance(ret.type.type, Contract)
else str(ret.type) else str(ret.type)
for ret in func.returns for ret in func.returns
] ]
@ -81,6 +118,8 @@ def generate_interface_function_signature(
else f"{str(param.type.type)} memory" else f"{str(param.type.type)} memory"
if isinstance(param.type, UserDefinedType) if isinstance(param.type, UserDefinedType)
and isinstance(param.type.type, (Structure, Enum)) and isinstance(param.type.type, (Structure, Enum))
else "address"
if isinstance(param.type, UserDefinedType) and isinstance(param.type.type, Contract)
else str(param.type) else str(param.type)
for param in func.parameters for param in func.parameters
] ]

Loading…
Cancel
Save