diff --git a/slither/detectors/abstract_detector.py b/slither/detectors/abstract_detector.py index 0763ea75c..2a1869609 100644 --- a/slither/detectors/abstract_detector.py +++ b/slither/detectors/abstract_detector.py @@ -140,20 +140,30 @@ class AbstractDetector(metaclass=abc.ABCMeta): def color(self): return classification_colors[self.IMPACT] - def generate_json_result(self, info): + def generate_json_result(self, info, additional_fields={}): d = OrderedDict() d['check'] = self.ARGUMENT d['impact'] = classification_txt[self.IMPACT] d['confidence'] = classification_txt[self.CONFIDENCE] d['description'] = info d['elements'] = [] + if additional_fields: + d['additional_fields'] = additional_fields return d @staticmethod - def add_variable_to_json(variable, d): - d['elements'].append({'type': 'variable', - 'name': variable.name, - 'source_mapping': variable.source_mapping}) + def _create_base_element(type, name, source_mapping, additional_fields={}): + element = {'type': type, + 'name': name, + 'source_mapping': source_mapping} + if additional_fields: + element['additional_fields'] = additional_fields + return element + + @staticmethod + def add_variable_to_json(variable, d, additional_fields={}): + element = AbstractDetector._create_base_element('variable', variable.name, variable.source_mapping, additional_fields) + d['elements'].append(element) @staticmethod def add_variables_to_json(variables, d): @@ -161,29 +171,48 @@ class AbstractDetector(metaclass=abc.ABCMeta): AbstractDetector.add_variable_to_json(variable, d) @staticmethod - def add_contract_to_json(contract, d): - d['elements'].append({'type': 'contract', - 'name': contract.name, - 'source_mapping': contract.source_mapping}) + def add_contract_to_json(contract, d, additional_fields={}): + element = AbstractDetector._create_base_element('contract', contract.name, contract.source_mapping, additional_fields) + d['elements'].append(element) @staticmethod - def add_function_to_json(function, d): + def add_function_to_json(function, d, additional_fields={}): contract = {'elements':[]} AbstractDetector.add_contract_to_json(function.contract, contract) - d['elements'].append({'type': 'function', - 'name': function.name, - 'source_mapping': function.source_mapping, - 'contract': contract['elements'][0]}) + element = AbstractDetector._create_base_element('function', function.name, function.source_mapping, additional_fields) + element['contract'] = contract['elements'][0] + d['elements'].append(element) @staticmethod def add_functions_to_json(functions, d): for function in sorted(functions, key=lambda x: x.name): AbstractDetector.add_function_to_json(function, d) + @staticmethod + def add_enum_to_json(enum, d, additional_fields={}): + element = AbstractDetector._create_base_element('enum', enum.name, enum.source_mapping, additional_fields) + d['elements'].append(element) + + @staticmethod + def add_struct_to_json(struct, d, additional_fields={}): + element = AbstractDetector._create_base_element('struct', struct.name, struct.source_mapping, additional_fields) + d['elements'].append(element) + + @staticmethod + def add_event_to_json(event, d, additional_fields={}): + contract = {'elements':[]} + AbstractDetector.add_contract_to_json(event.contract, contract) + element = AbstractDetector._create_base_element('event', event.name, event.source_mapping, additional_fields) + element['contract'] = contract['elements'][0] + d['elements'].append(element) + + @staticmethod + def add_node_to_json(node, d, additional_fields={}): + element = AbstractDetector._create_base_element('expression', str(node.expression), node.source_mapping, additional_fields) + d['elements'].append(element) + @staticmethod def add_nodes_to_json(nodes, d): for node in sorted(nodes, key=lambda x: x.node_id): - d['elements'].append({'type': 'expression', - 'expression': str(node.expression), - 'source_mapping': node.source_mapping}) + AbstractDetector.add_node_to_json(node, d) diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 545d14e06..e0e9619bf 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -61,12 +61,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 contract.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'contract' - elem['convention'] = 'CapWords' - elem['name'] = contract.name - elem['source_mapping'] = contract.source_mapping - json['elements'] = [elem] + self.add_contract_to_json(contract, json, { + "target": "contract", + "convention": "CapWords" + }) results.append(json) for struct in contract.structures: @@ -78,13 +76,12 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(struct.contract.name, struct.name, struct.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'structure' - elem['convention'] = 'CapWords' - elem['name'] = struct.name - elem['source_mapping'] = struct.source_mapping - json['elements'] = [elem] + self.add_struct_to_json(struct, json, { + "target": "structure", + "convention": "CapWords" + }) results.append(json) + for event in contract.events: if event.contract != contract: continue @@ -94,12 +91,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(event.contract.name, event.name, event.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'event' - elem['convention'] = 'CapWords' - elem['name'] = event.name - elem['source_mapping'] = event.source_mapping - json['elements'] = [elem] + self.add_event_to_json(event, json, { + "target": "event", + "convention": "CapWords" + }) results.append(json) for func in contract.functions: @@ -111,12 +106,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(func.contract.name, func.name, func.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'function' - elem['convention'] = 'mixedCase' - elem['name'] = func.name - elem['source_mapping'] = func.source_mapping - json['elements'] = [elem] + self.add_function_to_json(func, json, { + "target": "function", + "convention": "mixedCase" + }) results.append(json) for argument in func.parameters: @@ -132,12 +125,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 argument.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'parameter' - elem['convention'] = 'mixedCase' - elem['name'] = argument.name - elem['source_mapping'] = argument.source_mapping - json['elements'] = [elem] + self.add_variable_to_json(argument, json, { + "target": "parameter", + "convention": "mixedCase" + }) results.append(json) for var in contract.state_variables: @@ -150,12 +141,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(var.contract.name, var.name, var.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'variable' - elem['convention'] = 'l_O_I_should_not_be_used' - elem['name'] = var.name - elem['source_mapping'] = var.source_mapping - json['elements'] = [elem] + self.add_variable_to_json(var, json, { + "target": "variable", + "convention": "l_O_I_should_not_be_used" + }) results.append(json) if var.is_constant is True: @@ -168,12 +157,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(var.contract.name, var.name, var.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'variable_constant' - elem['convention'] = 'UPPER_CASE_WITH_UNDERSCORES' - elem['name'] = var.name - elem['source_mapping'] = var.source_mapping - json['elements'] = [elem] + self.add_variable_to_json(var, json, { + "target": "variable_constant", + "convention": "UPPER_CASE_WITH_UNDERSCORES" + }) results.append(json) else: @@ -186,12 +173,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(var.contract.name, var.name, var.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'variable' - elem['convention'] = 'mixedCase' - elem['name'] = var.name - elem['source_mapping'] = var.source_mapping - json['elements'] = [elem] + self.add_variable_to_json(var, json, { + "target": "variable", + "convention": "mixedCase" + }) results.append(json) for enum in contract.enums: @@ -203,12 +188,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(enum.contract.name, enum.name, enum.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'enum' - elem['convention'] = 'CapWords' - elem['name'] = enum.name - elem['source_mapping'] = enum.source_mapping - json['elements'] = [elem] + self.add_enum_to_json(enum, json, { + "target": "enum", + "convention": "CapWords" + }) results.append(json) @@ -223,12 +206,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 modifier.source_mapping_str) json = self.generate_json_result(info) - elem = dict() - elem['target'] = 'modifier' - elem['convention'] = 'mixedCase' - elem['name'] = modifier.name - elem['source_mapping'] = modifier.source_mapping - json['elements'] = [elem] + self.add_function_to_json(modifier, json, { + "target": "modifier", + "convention": "mixedCase" + }) results.append(json) diff --git a/slither/detectors/shadowing/builtin_symbols.py b/slither/detectors/shadowing/builtin_symbols.py index dc9981c41..35d9bccf4 100644 --- a/slither/detectors/shadowing/builtin_symbols.py +++ b/slither/detectors/shadowing/builtin_symbols.py @@ -143,8 +143,10 @@ contract Bug { # Generate relevant JSON data for this shadowing definition. json = self.generate_json_result(info) - if shadow_type in [self.SHADOWING_FUNCTION, self.SHADOWING_MODIFIER, self.SHADOWING_EVENT]: + if shadow_type in [self.SHADOWING_FUNCTION, self.SHADOWING_MODIFIER]: self.add_function_to_json(shadow_object, json) + elif shadow_type == self.SHADOWING_EVENT: + self.add_event_to_json(shadow_object, json) elif shadow_type in [self.SHADOWING_STATE_VARIABLE, self.SHADOWING_LOCAL_VARIABLE]: self.add_variable_to_json(shadow_object, json) results.append(json)