Move code generation to a new util

Rather than on the core objects.
pull/1730/head
webthethird 2 years ago
parent 0df2c23eee
commit c507b3b99f
  1. 19
      slither/core/declarations/contract.py
  2. 35
      slither/core/declarations/function.py
  3. 6
      slither/core/declarations/structure.py
  4. 94
      slither/utils/code_generation.py

@ -953,25 +953,6 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
""" """
return all((not f.is_implemented) for f in self.functions) return all((not f.is_implemented) for f in self.functions)
def generate_interface(self) -> str:
interface = f"interface I{self.name} {{\n"
for event in self.events:
name, args = event.signature
interface += f" event {name}({','.join(args)});\n"
for struct in self.structures:
if isinstance(struct.interface_def_str(), str):
interface += struct.interface_def_str()
for var in self.state_variables_entry_points:
interface += (
f" function {var.signature_str.replace('returns', 'external returns ')};\n"
)
for func in self.functions_entry_points:
if func.is_constructor or func.is_fallback or func.is_receive:
continue
interface += f" function {func.interface_signature_str};\n"
interface += "}\n\n"
return interface
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -1004,41 +1004,6 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
) )
return self._signature_str return self._signature_str
@property
def interface_signature_str(self) -> Optional[str]:
"""
str: func_name(type1,type2) external {payable/view/pure} returns (type3)
Return the function interface as a str (contains the return values)
Returns None if the function is private or internal, or is a constructor/fallback/receive
"""
from slither.core.declarations.contract import Contract
if self._interface_signature_str is None:
name, parameters, return_vars = self.signature
visibility = self.visibility
if (
visibility in ["private", "internal"]
or self.is_constructor
or self.is_fallback
or self.is_receive
):
return None
view = " view" if self.view else ""
pure = " pure" if self.pure else ""
payable = " payable" if self.payable else ""
returns = [
"address"
if isinstance(ret.type, UserDefinedType) and isinstance(ret.type.type, Contract)
else str(ret.type)
for ret in self.returns
]
self._interface_signature_str = (
name + "(" + ",".join(parameters) + ") external" + payable + pure + view
)
if len(return_vars) > 0:
self._interface_signature_str += " returns (" + ",".join(returns) + ")"
return self._interface_signature_str
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -49,11 +49,5 @@ class Structure(SourceMapping):
ret.append(self._elems[e]) ret.append(self._elems[e])
return ret return ret
def interface_def_str(self) -> str:
definition = f" struct {self.name} {{\n"
for elem in self.elems_ordered:
definition += f" {elem.type} {elem.name};\n"
definition += " }\n"
def __str__(self) -> str: def __str__(self) -> str:
return self.name return self.name

@ -0,0 +1,94 @@
# Functions for generating Solidity code
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from slither.core.declarations import Function, Contract, Structure
def generate_interface(contract: "Contract") -> str:
"""
Generates code for a Solidity interface to the contract.
Args:
contract: A Contract object
Returns:
A string with the code for an interface, with function stubs for all public or external functions and
state variables, as well as any events or structs declared in the contract.
"""
interface = f"interface I{contract.name} {{\n"
for event in contract.events:
name, args = event.signature
interface += f" event {name}({','.join(args)});\n"
for struct in contract.structures:
interface += generate_struct_interface_str(struct)
for var in contract.state_variables_entry_points:
interface += (
f" function {var.signature_str.replace('returns', 'external returns ')};\n"
)
for func in contract.functions_entry_points:
if func.is_constructor or func.is_fallback or func.is_receive:
continue
interface += f" function {generate_interface_function_signature(func)};\n"
interface += "}\n\n"
return interface
def generate_interface_function_signature(func: "Function") -> Optional[str]:
"""
Generates a string of the form:
func_name(type1,type2) external {payable/view/pure} returns (type3)
Args:
func: A Function object
Returns:
The function interface as a str (contains the return values).
Returns None if the function is private or internal, or is a constructor/fallback/receive.
"""
from slither.core.declarations.contract import Contract
name, parameters, return_vars = func.signature
visibility = func.visibility
if (
visibility in ["private", "internal"]
or func.is_constructor
or func.is_fallback
or func.is_receive
):
return None
view = " view" if func.view else ""
pure = " pure" if func.pure else ""
payable = " payable" if func.payable else ""
returns = [
"address"
if isinstance(ret.type, UserDefinedType) and isinstance(ret.type.type, Contract)
else str(ret.type)
for ret in func.returns
]
_interface_signature_str = (
name + "(" + ",".join(parameters) + ") external" + payable + pure + view
)
if len(return_vars) > 0:
_interface_signature_str += " returns (" + ",".join(returns) + ")"
return _interface_signature_str
def generate_struct_interface_str(struct: "Structure") -> str:
"""
Generates code for a structure declaration in an interface of the form:
struct struct_name {
elem1_type elem1_name;
elem2_type elem2_name;
... ...
}
Args:
struct: A Structure object
Returns:
The structure declaration code as a string.
"""
definition = f" struct {struct.name} {{\n"
for elem in struct.elems_ordered:
definition += f" {elem.type} {elem.name};\n"
definition += " }\n"
return definition
Loading…
Cancel
Save