Adds printer for inheritance and updates inheritance-graph printer

pull/42/head
Praveen Gupta 6 years ago
parent 265a7d6a17
commit bd1a056dd9
  1. 3
      README.md
  2. 136
      slither/printers/inheritance/inheritance.py
  3. 122
      slither/printers/inheritance/inheritance_graph.py

@ -41,7 +41,8 @@ If Slither is run on a directory, it will run on every `.sol` file of the direct
* `--printer-summary`: Print a summary of the contracts
* `--printer-quick-summary`: Print a quick summary of the contracts
* `--printer-inheritance`: Print the inheritance graph
* `--printer-inheritance`: Print the inheritance relations
* `--printer-inheritance-graph`: Print the inheritance graph in a file
* `--printer-vars-and-auth`: Print the variables written and the check on `msg.sender` of each function
## Checks available

@ -1,123 +1,45 @@
"""
Module printing the inheritance graph
Module printing the inheritance relation
The inheritance graph shows the relation between the contracts
and their functions/modifiers/public variables.
The output is a dot file named filename.dot
The inheritance shows the relation between the contracts
"""
from slither.core.declarations.contract import Contract
from slither.detectors.shadowing.shadowing_functions import ShadowingFunctionsDetection
from slither.printers.abstract_printer import AbstractPrinter
from slither.utils.colors import blue, green, magenta
class PrinterInheritance(AbstractPrinter):
ARGUMENT = 'inheritance'
HELP = 'the inheritance graph'
HELP = 'the inheritance relation between contracts'
def __init__(self, slither, logger):
super(PrinterInheritance, self).__init__(slither, logger)
inheritance = [x.inheritance for x in slither.contracts]
self.inheritance = set([item for sublist in inheritance for item in sublist])
shadow = ShadowingFunctionsDetection(slither, None)
ret = shadow.detect()
functions_shadowed = {}
for s in ret:
if s['contractShadower'] not in functions_shadowed:
functions_shadowed[s['contractShadower']] = []
functions_shadowed[s['contractShadower']] += s['funcs']
self.functions_shadowed = functions_shadowed
def _get_pattern_func(self, func, contract):
# Html pattern, each line is a row in a table
func_name = func.full_name
pattern = '<TR><TD align="left"> %s</TD></TR>'
pattern_shadow = '<TR><TD align="left"><font color="#FFA500"> %s</font></TD></TR>'
if contract.name in self.functions_shadowed:
if func_name in self.functions_shadowed[contract.name]:
return pattern_shadow % func_name
return pattern % func_name
def _get_pattern_var(self, var, contract):
# Html pattern, each line is a row in a table
var_name = var.name
pattern = '<TR><TD align="left"> %s</TD></TR>'
pattern_contract = '<TR><TD align="left"> %s<font color="blue" POINT-SIZE="10"> (%s)</font></TD></TR>'
# pattern_arrow = '<TR><TD align="left" PORT="%s"><font color="blue"> %s</font></TD></TR>'
if isinstance(var.type, Contract):
return pattern_contract % (var_name, str(var.type))
# return pattern_arrow%(self._get_port_id(var, contract), var_name)
return pattern % var_name
def _get_port_id(self, var, contract):
return "%s%s" % (var.name, contract.name)
def _summary(self, contract):
"""
Build summary using HTML
"""
ret = ''
# Add arrows
for i in contract.inheritance:
ret += '%s -> %s;\n' % (contract.name, i)
# Functions
visibilities = ['public', 'external']
public_functions = [self._get_pattern_func(f, contract) for f in contract.functions if
not f.is_constructor and f.contract == contract and f.visibility in visibilities]
public_functions = ''.join(public_functions)
private_functions = [self._get_pattern_func(f, contract) for f in contract.functions if
not f.is_constructor and f.contract == contract and f.visibility not in visibilities]
private_functions = ''.join(private_functions)
# Modifiers
modifiers = [self._get_pattern_func(m, contract) for m in contract.modifiers if m.contract == contract]
modifiers = ''.join(modifiers)
# Public variables
public_variables = [self._get_pattern_var(v, contract) for v in contract.variables if
v.visibility in visibilities]
public_variables = ''.join(public_variables)
private_variables = [self._get_pattern_var(v, contract) for v in contract.variables if
not v.visibility in visibilities]
private_variables = ''.join(private_variables)
# Build the node label
ret += '%s[shape="box"' % contract.name
ret += 'label=< <TABLE border="0">'
ret += '<TR><TD align="center"><B>%s</B></TD></TR>' % contract.name
if public_functions:
ret += '<TR><TD align="left"><I>Public Functions:</I></TD></TR>'
ret += '%s' % public_functions
if private_functions:
ret += '<TR><TD align="left"><I>Private Functions:</I></TD></TR>'
ret += '%s' % private_functions
if modifiers:
ret += '<TR><TD align="left"><I>Modifiers:</I></TD></TR>'
ret += '%s' % modifiers
if public_variables:
ret += '<TR><TD align="left"><I>Public Variables:</I></TD></TR>'
ret += '%s' % public_variables
if private_variables:
ret += '<TR><TD align="left"><I>Private Variables:</I></TD></TR>'
ret += '%s' % private_variables
ret += '</TABLE> >];\n'
return ret
def _get_child_contracts(self, base):
for child in self.contracts:
if base in child.inheritance:
yield child
def output(self, filename):
"""
Output the graph in filename
Output the inheritance relation
_filename is not used
Args:
filename(string)
_filename(string)
"""
if not filename.endswith('.dot'):
filename += ".dot"
info = 'Inheritance Graph: ' + filename
info = 'Inheritance\n'
info += blue('Child_Contract -> ') + green('Base_Contracts')
for contract in self.contracts:
info += blue(f'\n+ {contract.name} -> ')
if contract.inheritance:
info += green(", ".join(map(str, contract.inheritance)))
else:
info += magenta("Root_Contract")
info += green('\n\nBase_Contract -> ') + blue('Child_Contracts')
for contract in self.contracts:
info += green(f'\n+ {contract.name} -> ')
children = list(self._get_child_contracts(contract))
if children:
info += blue(", ".join(map(str, children)))
else:
info += magenta("Leaf_Contract")
self.info(info)
with open(filename, 'w') as f:
f.write('digraph{\n')
for c in self.contracts:
f.write(self._summary(c))
f.write('}')

@ -0,0 +1,122 @@
"""
Module printing the inheritance graph
The inheritance graph shows the relation between the contracts
and their functions/modifiers/public variables.
The output is a dot file named filename.dot
"""
from slither.core.declarations.contract import Contract
from slither.detectors.shadowing.shadowing_functions import ShadowingFunctionsDetection
from slither.printers.abstract_printer import AbstractPrinter
class PrinterInheritanceGraph(AbstractPrinter):
ARGUMENT = 'inheritance-graph'
HELP = 'the inheritance graph'
def __init__(self, slither, logger):
super(PrinterInheritanceGraph, self).__init__(slither, logger)
inheritance = [x.inheritance for x in slither.contracts]
self.inheritance = set([item for sublist in inheritance for item in sublist])
shadow = ShadowingFunctionsDetection(slither, None)
ret = shadow.detect()
functions_shadowed = {}
for s in ret:
if s['contractShadower'] not in functions_shadowed:
functions_shadowed[s['contractShadower']] = []
functions_shadowed[s['contractShadower']] += s['funcs']
self.functions_shadowed = functions_shadowed
def _get_pattern_func(self, func, contract):
# Html pattern, each line is a row in a table
func_name = func.full_name
pattern = '<TR><TD align="left"> %s</TD></TR>'
pattern_shadow = '<TR><TD align="left"><font color="#FFA500"> %s</font></TD></TR>'
if contract.name in self.functions_shadowed:
if func_name in self.functions_shadowed[contract.name]:
return pattern_shadow % func_name
return pattern % func_name
def _get_pattern_var(self, var, contract):
# Html pattern, each line is a row in a table
var_name = var.name
pattern = '<TR><TD align="left"> %s</TD></TR>'
pattern_contract = '<TR><TD align="left"> %s<font color="blue" POINT-SIZE="10"> (%s)</font></TD></TR>'
# pattern_arrow = '<TR><TD align="left" PORT="%s"><font color="blue"> %s</font></TD></TR>'
if isinstance(var.type, Contract):
return pattern_contract % (var_name, str(var.type))
# return pattern_arrow%(self._get_port_id(var, contract), var_name)
return pattern % var_name
def _get_port_id(self, var, contract):
return "%s%s" % (var.name, contract.name)
def _summary(self, contract):
"""
Build summary using HTML
"""
ret = ''
# Add arrows
for i in contract.inheritance:
ret += '%s -> %s;\n' % (contract.name, i)
# Functions
visibilities = ['public', 'external']
public_functions = [self._get_pattern_func(f, contract) for f in contract.functions if
not f.is_constructor and f.contract == contract and f.visibility in visibilities]
public_functions = ''.join(public_functions)
private_functions = [self._get_pattern_func(f, contract) for f in contract.functions if
not f.is_constructor and f.contract == contract and f.visibility not in visibilities]
private_functions = ''.join(private_functions)
# Modifiers
modifiers = [self._get_pattern_func(m, contract) for m in contract.modifiers if m.contract == contract]
modifiers = ''.join(modifiers)
# Public variables
public_variables = [self._get_pattern_var(v, contract) for v in contract.variables if
v.visibility in visibilities]
public_variables = ''.join(public_variables)
private_variables = [self._get_pattern_var(v, contract) for v in contract.variables if
not v.visibility in visibilities]
private_variables = ''.join(private_variables)
# Build the node label
ret += '%s[shape="box"' % contract.name
ret += 'label=< <TABLE border="0">'
ret += '<TR><TD align="center"><B>%s</B></TD></TR>' % contract.name
if public_functions:
ret += '<TR><TD align="left"><I>Public Functions:</I></TD></TR>'
ret += '%s' % public_functions
if private_functions:
ret += '<TR><TD align="left"><I>Private Functions:</I></TD></TR>'
ret += '%s' % private_functions
if modifiers:
ret += '<TR><TD align="left"><I>Modifiers:</I></TD></TR>'
ret += '%s' % modifiers
if public_variables:
ret += '<TR><TD align="left"><I>Public Variables:</I></TD></TR>'
ret += '%s' % public_variables
if private_variables:
ret += '<TR><TD align="left"><I>Private Variables:</I></TD></TR>'
ret += '%s' % private_variables
ret += '</TABLE> >];\n'
return ret
def output(self, filename):
"""
Output the graph in filename
Args:
filename(string)
"""
if not filename.endswith('.dot'):
filename += ".dot"
info = 'Inheritance Graph: ' + filename
self.info(info)
with open(filename, 'w') as f:
f.write('digraph{\n')
for c in self.contracts:
f.write(self._summary(c))
f.write('}')
Loading…
Cancel
Save