From 1cd7dc80d56940a3c96363041c5333dd84012fbb Mon Sep 17 00:00:00 2001 From: Josselin Date: Mon, 4 Nov 2019 10:18:51 +0100 Subject: [PATCH] Add self.add_X_to_json to AbstractPrinter Refactor contract summary and human summary --- slither/__main__.py | 5 +- slither/printers/abstract_printer.py | 28 ++++++++- slither/printers/call/call_graph.py | 8 +-- slither/printers/functions/authorization.py | 3 +- slither/printers/functions/cfg.py | 4 +- slither/printers/inheritance/inheritance.py | 1 - .../printers/inheritance/inheritance_graph.py | 3 +- slither/printers/summary/contract.py | 57 +++++++++---------- slither/printers/summary/data_depenency.py | 2 +- slither/printers/summary/function.py | 3 +- slither/printers/summary/function_ids.py | 3 +- slither/printers/summary/human_summary.py | 8 ++- slither/printers/summary/modifier_calls.py | 3 +- slither/printers/summary/require_calls.py | 3 +- slither/printers/summary/slithir_ssa.py | 2 +- slither/printers/summary/variable_order.py | 3 +- 16 files changed, 74 insertions(+), 62 deletions(-) diff --git a/slither/__main__.py b/slither/__main__.py index a5f6dc4d6..f0e61894f 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -604,11 +604,12 @@ def main_impl(all_detector_classes, all_printer_classes): # Dont print the number of result for printers if number_contracts == 0: - logger.warn(red('No contract was analyzed')) + logger.warning(red('No contract was analyzed')) if printer_classes: logger.info('%s analyzed (%d contracts)', filename, number_contracts) else: - logger.info('%s analyzed (%d contracts with %d detectors), %d result(s) found', filename, number_contracts, len(detector_classes), len(results)) + logger.info('%s analyzed (%d contracts with %d detectors), %d result(s) found', filename, + number_contracts, len(detector_classes), len(results_detectors)) if args.ignore_return_value: return diff --git a/slither/printers/abstract_printer.py b/slither/printers/abstract_printer.py index 5f9cbd6c9..3c7331138 100644 --- a/slither/printers/abstract_printer.py +++ b/slither/printers/abstract_printer.py @@ -33,12 +33,38 @@ class AbstractPrinter(metaclass=abc.ABCMeta): self.logger.info(info) - def generate_json_result(self, info, additional_fields={}): + def generate_json_result(self, info, additional_fields=None): + if additional_fields is None: + additional_fields = {} d = json_utils.generate_json_result(info, additional_fields) d['printer'] = self.ARGUMENT return d + @staticmethod + def add_contract_to_json(e, d, additional_fields=None): + json_utils.add_contract_to_json(e, d, additional_fields=additional_fields) + + @staticmethod + def add_function_to_json(e, d, additional_fields=None): + json_utils.add_function_to_json(e, d, additional_fields=additional_fields) + + @staticmethod + def add_functions_to_json(e, d, additional_fields=None): + json_utils.add_functions_to_json(e, d, additional_fields=additional_fields) + + @staticmethod + def add_file_to_json(e, content, d, additional_fields=None): + json_utils.add_file_to_json(e, content, d, additional_fields) + + @staticmethod + def add_pretty_table_to_json(e, content, d, additional_fields=None): + json_utils.add_pretty_table_to_json(e, content, d, additional_fields) + + @staticmethod + def add_other_to_json(name, source_mapping, d, slither, additional_fields=None): + json_utils.add_other_to_json(name, source_mapping, d, slither, additional_fields) + @abc.abstractmethod def output(self, filename): """TODO Documentation""" diff --git a/slither/printers/call/call_graph.py b/slither/printers/call/call_graph.py index 285635163..2f224ece0 100644 --- a/slither/printers/call/call_graph.py +++ b/slither/printers/call/call_graph.py @@ -9,14 +9,8 @@ from collections import defaultdict from slither.printers.abstract_printer import AbstractPrinter from slither.core.declarations.solidity_variables import SolidityFunction from slither.core.declarations.function import Function -from slither.core.declarations.contract import Contract -from slither.core.expressions.member_access import MemberAccess -from slither.core.expressions.identifier import Identifier from slither.core.variables.variable import Variable -from slither.core.solidity_types.user_defined_type import UserDefinedType -# return unique id for contract to use as subgraph name -from slither.utils import json_utils def _contract_subgraph(contract): @@ -184,7 +178,7 @@ class PrinterCallGraph(AbstractPrinter): self.info(info) json = self.generate_json_result(info) for filename, content in results: - json_utils.add_file_to_json(filename, content, json) + self.add_file_to_json(filename, content, json) return json diff --git a/slither/printers/functions/authorization.py b/slither/printers/functions/authorization.py index e934c28d7..72fc532b3 100644 --- a/slither/printers/functions/authorization.py +++ b/slither/printers/functions/authorization.py @@ -5,7 +5,6 @@ from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter from slither.core.declarations.function import Function -from slither.utils import json_utils class PrinterWrittenVariablesAndAuthorization(AbstractPrinter): @@ -51,6 +50,6 @@ class PrinterWrittenVariablesAndAuthorization(AbstractPrinter): self.info(txt) json = self.generate_json_result(txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json \ No newline at end of file diff --git a/slither/printers/functions/cfg.py b/slither/printers/functions/cfg.py index 09a76a1c6..191d63b5c 100644 --- a/slither/printers/functions/cfg.py +++ b/slither/printers/functions/cfg.py @@ -2,8 +2,6 @@ """ from slither.printers.abstract_printer import AbstractPrinter -from slither.core.declarations.function import Function -from slither.utils import json_utils class CFG(AbstractPrinter): @@ -35,5 +33,5 @@ class CFG(AbstractPrinter): json = self.generate_json_result(info) for filename, content in all_files: - json_utils.add_file_to_json(filename, content, json) + self.add_file_to_json(filename, content, json) return json \ No newline at end of file diff --git a/slither/printers/inheritance/inheritance.py b/slither/printers/inheritance/inheritance.py index d151b6486..f3b970dfc 100644 --- a/slither/printers/inheritance/inheritance.py +++ b/slither/printers/inheritance/inheritance.py @@ -5,7 +5,6 @@ """ from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils from slither.utils.colors import blue, green diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index 529c4bdd9..52f4f32e2 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -9,7 +9,6 @@ from slither.core.declarations.contract import Contract from slither.core.solidity_types.user_defined_type import UserDefinedType from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils from slither.utils.inheritance_analysis import (detect_c3_function_shadowing, detect_state_variable_shadowing) @@ -174,6 +173,6 @@ class PrinterInheritanceGraph(AbstractPrinter): f.write(content) json = self.generate_json_result(info) - json_utils.add_file_to_json(filename, content, json) + self.add_file_to_json(filename, content, json) return json \ No newline at end of file diff --git a/slither/printers/summary/contract.py b/slither/printers/summary/contract.py index ef4d13d6a..df7742281 100644 --- a/slither/printers/summary/contract.py +++ b/slither/printers/summary/contract.py @@ -3,11 +3,10 @@ """ import collections from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils from slither.utils.colors import blue, green, magenta -class ContractSummary(AbstractPrinter): +class ContractSummary(AbstractPrinter): ARGUMENT = 'contract-summary' HELP = 'Print a summary of the contracts' @@ -21,42 +20,42 @@ class ContractSummary(AbstractPrinter): """ txt = "" - result = {} + + all_contracts = [] for c in self.contracts: - (name, _inheritance, _var, func_summaries, _modif_summaries) = c.get_summary(False) - txt += blue("\n+ Contract %s\n"%name) - result[name] = {} - # (c_name, f_name, visi, _, _, _, _, _) in func_summaries - public = [(elem[0], (elem[1], elem[2]) ) for elem in func_summaries] + txt += blue("\n+ Contract %s\n" % c.name) + additional_fields = {"elements": []} + # Order the function with + # contract_declarer -> list_functions + public = [(f.contract_declarer.name, f) for f in c.functions if (not f.is_shadowed)] collect = collections.defaultdict(list) - for a,b in public: + for a, b in public: collect[a].append(b) public = list(collect.items()) for contract, functions in public: txt += blue(" - From {}\n".format(contract)) - result[name]['from'] = str(contract) - functions = sorted(functions) - result[name]['functions'] = {} - result[name]['functions']['visible'] = [] - result[name]['functions']['invisible'] = [] - result[name]['functions']['others'] = [] - for (function, visi) in functions: - if visi in ['external', 'public']: - result[name]['functions']['visible'].append({'function': function, 'visi': visi}) - txt += green(" - {} ({})\n".format(function, visi)) - for (function, visi) in functions: - if visi in ['internal', 'private']: - result[name]['functions']['invisible'].append({'function': function, 'visi': visi}) - txt += magenta(" - {} ({})\n".format(function, visi)) - for (function, visi) in functions: - if visi not in ['external', 'public', 'internal', 'private']: - result[name]['functions']['others'].append({'function': function, 'visi': visi}) - txt += " - {}  ({})\n".format(function, visi) + + functions = sorted(functions, key=lambda f: f.full_name) + + for function in functions: + if function.visibility in ['external', 'public']: + txt += green(" - {} ({})\n".format(function, function.visibility)) + if function.visibility in ['internal', 'private']: + txt += magenta(" - {} ({})\n".format(function, function.visibility)) + if function.visibility not in ['external', 'public', 'internal', 'private']: + txt += " - {}  ({})\n".format(function, function.visibility) + + self.add_function_to_json(function, additional_fields, additional_fields={"visibility": + function.visibility}) + + all_contracts.append((c, additional_fields)) self.info(txt) - json = self.generate_json_result(txt, additional_fields=result) + json = self.generate_json_result(txt) + for contract, additional_fields in all_contracts: + self.add_contract_to_json(contract, json, additional_fields=additional_fields) - return json \ No newline at end of file + return json diff --git a/slither/printers/summary/data_depenency.py b/slither/printers/summary/data_depenency.py index e30814f81..cbd36fcdb 100644 --- a/slither/printers/summary/data_depenency.py +++ b/slither/printers/summary/data_depenency.py @@ -53,6 +53,6 @@ class DataDependency(AbstractPrinter): json = self.generate_json_result(all_txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json diff --git a/slither/printers/summary/function.py b/slither/printers/summary/function.py index b9659cf03..e9a71a965 100644 --- a/slither/printers/summary/function.py +++ b/slither/printers/summary/function.py @@ -4,7 +4,6 @@ from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils class FunctionSummary(AbstractPrinter): @@ -73,6 +72,6 @@ class FunctionSummary(AbstractPrinter): json = self.generate_json_result(all_txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json diff --git a/slither/printers/summary/function_ids.py b/slither/printers/summary/function_ids.py index 44bf9d7c6..5aee6529c 100644 --- a/slither/printers/summary/function_ids.py +++ b/slither/printers/summary/function_ids.py @@ -4,7 +4,6 @@ from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils from slither.utils.function import get_function_id class FunctionIds(AbstractPrinter): @@ -40,6 +39,6 @@ class FunctionIds(AbstractPrinter): json = self.generate_json_result(txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json \ No newline at end of file diff --git a/slither/printers/summary/human_summary.py b/slither/printers/summary/human_summary.py index fcd635365..156e353fa 100644 --- a/slither/printers/summary/human_summary.py +++ b/slither/printers/summary/human_summary.py @@ -4,7 +4,6 @@ Module printing summary of the contract import logging from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils from slither.utils.code_complexity import compute_cyclomatic_complexity from slither.utils.colors import green, red, yellow from slither.utils.standard_libraries import is_standard_library @@ -197,7 +196,9 @@ class PrinterHumanSummary(AbstractPrinter): txt += self._compilation_type() results = { - 'contracts': [], + 'contracts': { + "elements": [] + }, 'number_lines': 0, 'number_lines_in_dependencies': 0, 'standard_libraries': [], @@ -260,7 +261,8 @@ class PrinterHumanSummary(AbstractPrinter): else: contract_d['erc20_can_mint'] = False contract_d['erc20_race_condition_mitigated'] = race_condition_mitigated - results['contracts'].append(contract_d) + + self.add_contract_to_json(contract, results['contracts'], additional_fields=contract_d) json = self.generate_json_result(txt, additional_fields=results) diff --git a/slither/printers/summary/modifier_calls.py b/slither/printers/summary/modifier_calls.py index 858a813ff..fbc62c90d 100644 --- a/slither/printers/summary/modifier_calls.py +++ b/slither/printers/summary/modifier_calls.py @@ -5,7 +5,6 @@ from prettytable import PrettyTable from slither.core.declarations import Function from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils class Modifiers(AbstractPrinter): @@ -43,6 +42,6 @@ class Modifiers(AbstractPrinter): json = self.generate_json_result(all_txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json \ No newline at end of file diff --git a/slither/printers/summary/require_calls.py b/slither/printers/summary/require_calls.py index ab2874d67..51c67284d 100644 --- a/slither/printers/summary/require_calls.py +++ b/slither/printers/summary/require_calls.py @@ -6,7 +6,6 @@ from prettytable import PrettyTable from slither.core.declarations import SolidityFunction from slither.printers.abstract_printer import AbstractPrinter from slither.slithir.operations import SolidityCall -from slither.utils import json_utils require_or_assert = [SolidityFunction("assert(bool)"), SolidityFunction("require(bool)"), @@ -48,6 +47,6 @@ class RequireOrAssert(AbstractPrinter): json = self.generate_json_result(all_txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json diff --git a/slither/printers/summary/slithir_ssa.py b/slither/printers/summary/slithir_ssa.py index c97a291fa..37acd457e 100644 --- a/slither/printers/summary/slithir_ssa.py +++ b/slither/printers/summary/slithir_ssa.py @@ -3,7 +3,7 @@ """ from slither.printers.abstract_printer import AbstractPrinter -from slither.utils.colors import blue, green, magenta + class PrinterSlithIRSSA(AbstractPrinter): diff --git a/slither/printers/summary/variable_order.py b/slither/printers/summary/variable_order.py index d0debe60a..ffee1f940 100644 --- a/slither/printers/summary/variable_order.py +++ b/slither/printers/summary/variable_order.py @@ -4,7 +4,6 @@ from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter -from slither.utils import json_utils class VariableOrder(AbstractPrinter): @@ -39,6 +38,6 @@ class VariableOrder(AbstractPrinter): json = self.generate_json_result(txt) for name, table in all_tables: - json_utils.add_pretty_table_to_json(table, name, json) + self.add_pretty_table_to_json(table, name, json) return json \ No newline at end of file