- Add support for top level structures and enums

- Internally create a contract named SlitherInternalTopLevelContractX per
structure / enum
- Warm if user has a contract named SlitherInternalTopLevelContract
pull/499/head
Josselin 5 years ago
parent f8b5a1a9d6
commit b62cd9aca7
  1. 15
      slither/core/declarations/contract.py
  2. 39
      slither/solc_parsing/slitherSolc.py

@ -51,6 +51,8 @@ class Contract(ChildSlither, SourceMapping):
self._is_upgradeable = None self._is_upgradeable = None
self._is_upgradeable_proxy = None self._is_upgradeable_proxy = None
self._is_top_level = False
self._initial_state_variables = [] # ssa self._initial_state_variables = [] # ssa
@ -935,6 +937,19 @@ class Contract(ChildSlither, SourceMapping):
""" """
return self._is_incorrectly_parsed return self._is_incorrectly_parsed
@property
def is_top_level(self) -> bool:
"""
The "TopLevel" contract is used to hold structures and enums defined at the top level
ie. structures and enums that are represented outside of any contract
:return:
"""
return self._is_top_level
@is_top_level.setter
def is_top_level(self, t: bool):
self._is_top_level = t
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -2,6 +2,10 @@ import os
import json import json
import re import re
import logging import logging
from typing import Optional, List
from slither.core.declarations import Contract
from slither.exceptions import SlitherException
logging.basicConfig() logging.basicConfig()
logger = logging.getLogger("SlitherSolcParsing") logger = logging.getLogger("SlitherSolcParsing")
@ -25,6 +29,8 @@ class SlitherSolc(Slither):
self._is_compact_ast = False self._is_compact_ast = False
self._top_level_contracts_counter = 0
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region AST # region AST
@ -102,7 +108,11 @@ class SlitherSolc(Slither):
for contract_data in data_loaded[self.get_children()]: for contract_data in data_loaded[self.get_children()]:
assert contract_data[self.get_key()] in ['ContractDefinition', 'PragmaDirective', 'ImportDirective'] assert contract_data[self.get_key()] in ['ContractDefinition',
'PragmaDirective',
'ImportDirective',
'StructDefinition',
'EnumDefinition']
if contract_data[self.get_key()] == 'ContractDefinition': if contract_data[self.get_key()] == 'ContractDefinition':
contract = ContractSolc04(self, contract_data) contract = ContractSolc04(self, contract_data)
if 'src' in contract_data: if 'src' in contract_data:
@ -123,6 +133,30 @@ class SlitherSolc(Slither):
import_directive.set_offset(contract_data['src'], self) import_directive.set_offset(contract_data['src'], self)
self._import_directives.append(import_directive) self._import_directives.append(import_directive)
elif contract_data[self.get_key()] in ['StructDefinition', 'EnumDefinition']:
# This can only happen for top-level structure and enum
# They were introduced with 0.6.5
assert self._is_compact_ast # Do not support top level definition for legacy AST
fake_contract_data = {
'name': f'SlitherInternalTopLevelContract{self._top_level_contracts_counter}',
'id': -1000, # TODO: determine if collission possible
'linearizedBaseContracts': [],
'fullyImplemented': True,
'contractKind': 'SLitherInternal'
}
self._top_level_contracts_counter += 1
top_level_contract = ContractSolc04(self, fake_contract_data)
top_level_contract.is_top_level = True
top_level_contract.set_offset(contract_data['src'], self)
if contract_data[self.get_key()] == 'StructDefinition':
top_level_contract._structuresNotParsed.append(contract_data) # Todo add proper setters
else:
top_level_contract._enumsNotParsed.append(contract_data) # Todo add proper setters
self._contractsNotParsed.append(top_level_contract)
def _parse_source_unit(self, data, filename): def _parse_source_unit(self, data, filename):
if data[self.get_key()] != 'SourceUnit': if data[self.get_key()] != 'SourceUnit':
return -1 # handle solc prior 0.3.6 return -1 # handle solc prior 0.3.6
@ -178,6 +212,9 @@ class SlitherSolc(Slither):
# First we save all the contracts in a dict # First we save all the contracts in a dict
# the key is the contractid # the key is the contractid
for contract in self._contractsNotParsed: for contract in self._contractsNotParsed:
if contract.name.startswith('SlitherInternalTopLevelContract') and not contract.is_top_level:
raise SlitherException("""Your codebase has a contract named 'SlitherInternalTopLevelContract'.
Please rename it, this name is reserved for Slither's internals""")
if contract.name in self._contracts: if contract.name in self._contracts:
if contract.id != self._contracts[contract.name].id: if contract.id != self._contracts[contract.name].id:
self._contract_name_collisions[contract.name].append(contract.source_mapping_str) self._contract_name_collisions[contract.name].append(contract.source_mapping_str)

Loading…
Cancel
Save