@ -27,21 +27,23 @@ def _check_common_things(
) - > None :
if not issubclass ( cls , base_cls ) or cls is base_cls :
raise Exception (
raise SlitherError (
f " You can ' t register { cls !r} as a { thing_name } . You need to pass a class that inherits from { base_cls . __name__ } "
)
if any ( type ( obj ) == cls for obj in instances_list ) : # pylint: disable=unidiomatic-typecheck
raise Exception ( f " You can ' t register { cls !r} twice. " )
raise SlitherError ( f " You can ' t register { cls !r} twice. " )
def _update_file_scopes ( candidates : ValuesView [ FileScope ] ) :
def _update_file_scopes ( sol_parser : SlitherCompilationUnitSolc ) :
"""
Because solc ' s import allows cycle in the import
We iterate until we aren ' t adding new information to the scope
Since all definitions in a file are exported by default , including definitions from its ( transitive ) dependencies ,
we can identify all top level items that could possibly be referenced within the file from its exportedSymbols .
It is not as straightforward for user defined types and functions as well as aliasing . See add_accessible_scopes for more details .
"""
candidates = sol_parser . compilation_unit . scopes . values ( )
learned_something = False
# Because solc's import allows cycle in the import graph, iterate until we aren't adding new information to the scope.
while True :
for candidate in candidates :
learned_something | = candidate . add_accessible_scopes ( )
@ -49,6 +51,42 @@ def _update_file_scopes(candidates: ValuesView[FileScope]):
break
learned_something = False
for scope in candidates :
for refId in scope . exported_symbols :
if refId in sol_parser . contracts_by_id :
contract = sol_parser . contracts_by_id [ refId ]
scope . contracts [ contract . name ] = contract
elif refId in sol_parser . functions_by_id :
functions = sol_parser . functions_by_id [ refId ]
assert len ( functions ) == 1
function = functions [ 0 ]
scope . functions . add ( function )
elif refId in sol_parser . _imports_by_id :
import_directive = sol_parser . _imports_by_id [ refId ]
scope . imports . add ( import_directive )
elif refId in sol_parser . _top_level_variables_by_id :
top_level_variable = sol_parser . _top_level_variables_by_id [ refId ]
scope . variables [ top_level_variable . name ] = top_level_variable
elif refId in sol_parser . _top_level_events_by_id :
top_level_event = sol_parser . _top_level_events_by_id [ refId ]
scope . events . add ( top_level_event )
elif refId in sol_parser . _top_level_structures_by_id :
top_level_struct = sol_parser . _top_level_structures_by_id [ refId ]
scope . structures [ top_level_struct . name ] = top_level_struct
elif refId in sol_parser . _top_level_type_aliases_by_id :
top_level_type_alias = sol_parser . _top_level_type_aliases_by_id [ refId ]
scope . type_aliases [ top_level_type_alias . name ] = top_level_type_alias
elif refId in sol_parser . _top_level_enums_by_id :
top_level_enum = sol_parser . _top_level_enums_by_id [ refId ]
scope . enums [ top_level_enum . name ] = top_level_enum
elif refId in sol_parser . _top_level_errors_by_id :
top_level_custom_error = sol_parser . _top_level_errors_by_id [ refId ]
scope . custom_errors . add ( top_level_custom_error )
else :
logger . warning (
f " Failed to resolved name for reference id { refId } in { scope . filename } . "
)
class Slither (
SlitherCore
@ -118,12 +156,9 @@ class Slither(
sol_parser . parse_top_level_items ( ast , path )
self . add_source_code ( path )
_update_file_scopes ( compilation_unit_slither . scopes . values ( ) )
# First we save all the contracts in a dict
# the key is the contractid
for contract in sol_parser . _underlying_contract_to_parser :
if contract . name . startswith ( " SlitherInternalTopLevelContract " ) :
raise Exception (
raise SlitherError (
# region multi-line-string
""" Your codebase has a contract named ' SlitherInternalTopLevelContract ' .
Please rename it , this name is reserved for Slither ' s internals " " "
@ -131,48 +166,8 @@ class Slither(
)
sol_parser . _contracts_by_id [ contract . id ] = contract
sol_parser . _compilation_unit . contracts . append ( contract )
print ( " avalilable " )
for k , v in sol_parser . contracts_by_id . items ( ) :
print ( k , v . name )
for scope in compilation_unit_slither . scopes . values ( ) :
for refId in scope . exported_symbols :
print ( " scope " , scope )
print ( " target " , refId )
if refId in sol_parser . contracts_by_id :
contract = sol_parser . contracts_by_id [ refId ]
scope . contracts [ contract . name ] = contract
elif refId in sol_parser . functions_by_id :
print ( " found in functions " )
functions = sol_parser . functions_by_id [ refId ]
assert len ( functions ) == 1
function = functions [ 0 ]
scope . functions . add ( function )
elif refId in sol_parser . _imports_by_id :
import_directive = sol_parser . _imports_by_id [ refId ]
scope . imports . add ( import_directive )
elif refId in sol_parser . _top_level_variables_by_id :
top_level_variable = sol_parser . _top_level_variables_by_id [ refId ]
scope . variables [ top_level_variable . name ] = top_level_variable
elif refId in sol_parser . _top_level_events_by_id :
top_level_event = sol_parser . _top_level_events_by_id [ refId ]
scope . events . add ( top_level_event )
elif refId in sol_parser . _top_level_structures_by_id :
top_level_struct = sol_parser . _top_level_structures_by_id [ refId ]
scope . structures [ top_level_struct . name ] = top_level_struct
elif refId in sol_parser . _top_level_type_aliases_by_id :
top_level_type_alias = sol_parser . _top_level_type_aliases_by_id [ refId ]
scope . type_aliases [ top_level_type_alias . name ] = top_level_type_alias
elif refId in sol_parser . _top_level_enums_by_id :
top_level_enum = sol_parser . _top_level_enums_by_id [ refId ]
scope . enums [ top_level_enum . name ] = top_level_enum
elif refId in sol_parser . _top_level_errors_by_id :
print ( " found in errors " )
top_level_custom_error = sol_parser . _top_level_errors_by_id [ refId ]
print ( top_level_custom_error . name )
scope . custom_errors . add ( top_level_custom_error )
else :
print ( " not found " , refId )
assert False
_update_file_scopes ( sol_parser )
if kwargs . get ( " generate_patches " , False ) :
self . generate_patches = True