Browse Source

Fix all pylint issues

Josselin 4 months ago
parent
commit
70e609ec28
100 changed files with 1573 additions and 1087 deletions
  1. 0 87
      examples/scripts/call_graph.py
  2. 0 39
      examples/scripts/convert_to_evm_ins.py
  3. 2 2
      examples/scripts/convert_to_ir.py
  4. 2 2
      examples/scripts/data_dependency.py
  5. 1 1
      examples/scripts/export_dominator_tree_to_dot.py
  6. 1 1
      examples/scripts/export_to_dot.py
  7. 1 1
      examples/scripts/functions_called.py
  8. 1 1
      examples/scripts/functions_writing.py
  9. 6 6
      examples/scripts/possible_paths.py
  10. 1 1
      examples/scripts/slithIR.py
  11. 4 4
      examples/scripts/taint_mapping.py
  12. 1 1
      examples/scripts/variable_in_condition.py
  13. 8 1
      pyproject.toml
  14. 3 2
      scripts/json_diff.py
  15. 111 62
      slither/__main__.py
  16. 1 0
      slither/all_exceptions.py
  17. 37 10
      slither/analyses/data_dependency/data_dependency.py
  18. 24 13
      slither/analyses/evm/convert.py
  19. 1 0
      slither/analyses/evm/evm_cfg_builder.py
  20. 14 5
      slither/analyses/write/are_variables_written.py
  21. 69 27
      slither/core/cfg/node.py
  22. 1 1
      slither/core/children/child_node.py
  23. 1 1
      slither/core/context/context.py
  24. 5 1
      slither/core/declarations/__init__.py
  25. 130 47
      slither/core/declarations/contract.py
  26. 191 79
      slither/core/declarations/function.py
  27. 4 1
      slither/core/declarations/pragma_directive.py
  28. 9 4
      slither/core/declarations/solidity_variables.py
  29. 1 1
      slither/core/dominators/node_dominator_tree.py
  30. 1 0
      slither/core/dominators/utils.py
  31. 10 2
      slither/core/expressions/assignment_operation.py
  32. 12 4
      slither/core/expressions/binary_operation.py
  33. 1 1
      slither/core/expressions/call_expression.py
  34. 4 0
      slither/core/expressions/expression_typed.py
  35. 2 2
      slither/core/expressions/literal.py
  36. 0 1
      slither/core/expressions/super_call_expression.py
  37. 8 5
      slither/core/expressions/unary_operation.py
  38. 45 15
      slither/core/slither_core.py
  39. 3 1
      slither/core/solidity_types/elementary_type.py
  40. 3 1
      slither/core/solidity_types/function_type.py
  41. 1 0
      slither/core/solidity_types/type_information.py
  42. 6 3
      slither/core/solidity_types/user_defined_type.py
  43. 8 4
      slither/core/source_mapping/source_mapping.py
  44. 1 1
      slither/core/variables/event_variable.py
  45. 1 1
      slither/core/variables/local_variable.py
  46. 14 3
      slither/core/variables/state_variable.py
  47. 1 1
      slither/core/variables/structure_variable.py
  48. 4 1
      slither/core/variables/variable.py
  49. 21 9
      slither/detectors/abstract_detector.py
  50. 1 0
      slither/detectors/all_detectors.py
  51. 3 5
      slither/detectors/attributes/const_functions_asm.py
  52. 7 6
      slither/detectors/attributes/const_functions_state.py
  53. 2 2
      slither/detectors/attributes/constant_pragma.py
  54. 11 14
      slither/detectors/attributes/incorrect_solc.py
  55. 11 8
      slither/detectors/attributes/locked_ether.py
  56. 24 5
      slither/detectors/erc/incorrect_erc20_interface.py
  57. 41 14
      slither/detectors/erc/incorrect_erc721_interface.py
  58. 5 1
      slither/detectors/erc/unindexed_event_parameters.py
  59. 3 1
      slither/detectors/examples/backdoor.py
  60. 73 59
      slither/detectors/functions/arbitrary_send.py
  61. 0 105
      slither/detectors/functions/complex_function.py
  62. 23 17
      slither/detectors/functions/external_function.py
  63. 3 1
      slither/detectors/functions/suicidal.py
  64. 27 9
      slither/detectors/naming_convention/naming_convention.py
  65. 14 9
      slither/detectors/operations/block_timestamp.py
  66. 3 1
      slither/detectors/operations/low_level_calls.py
  67. 5 3
      slither/detectors/operations/unchecked_low_level_return_values.py
  68. 5 3
      slither/detectors/operations/unchecked_send_return_value.py
  69. 11 9
      slither/detectors/operations/unused_return_values.py
  70. 3 1
      slither/detectors/operations/void_constructor.py
  71. 37 26
      slither/detectors/reentrancy/reentrancy.py
  72. 26 16
      slither/detectors/reentrancy/reentrancy_benign.py
  73. 29 19
      slither/detectors/reentrancy/reentrancy_eth.py
  74. 22 16
      slither/detectors/reentrancy/reentrancy_events.py
  75. 30 22
      slither/detectors/reentrancy/reentrancy_no_gas.py
  76. 28 18
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  77. 16 15
      slither/detectors/shadowing/abstract.py
  78. 4 1
      slither/detectors/shadowing/builtin_symbols.py
  79. 12 4
      slither/detectors/shadowing/local.py
  80. 15 14
      slither/detectors/shadowing/state.py
  81. 13 5
      slither/detectors/slither/name_reused.py
  82. 23 21
      slither/detectors/source/rtlo.py
  83. 3 1
      slither/detectors/statements/assembly.py
  84. 15 5
      slither/detectors/statements/boolean_constant_equality.py
  85. 15 8
      slither/detectors/statements/boolean_constant_misuse.py
  86. 7 5
      slither/detectors/statements/calls_in_loop.py
  87. 21 17
      slither/detectors/statements/controlled_delegatecall.py
  88. 12 7
      slither/detectors/statements/deprecated_calls.py
  89. 11 4
      slither/detectors/statements/divide_before_multiply.py
  90. 20 11
      slither/detectors/statements/incorrect_strict_equality.py
  91. 3 1
      slither/detectors/statements/too_many_digits.py
  92. 1 3
      slither/detectors/statements/tx_origin.py
  93. 56 55
      slither/detectors/statements/type_based_tautology.py
  94. 22 13
      slither/detectors/variables/possible_const_state_variables.py
  95. 17 7
      slither/detectors/variables/uninitialized_local_variables.py
  96. 5 2
      slither/detectors/variables/uninitialized_state_variables.py
  97. 17 7
      slither/detectors/variables/uninitialized_storage_variables.py
  98. 41 34
      slither/detectors/variables/unused_state_variables.py
  99. 1 1
      slither/formatters/attributes/const_functions.py
  100. 0 0
      slither/formatters/attributes/constant_pragma.py

+ 0 - 87
examples/scripts/call_graph.py

@@ -1,87 +0,0 @@
-import os
-import logging
-import argparse
-from slither import Slither
-from slither.printers.all_printers import PrinterCallGraph
-from slither.core.declarations.function import Function
-
-logging.basicConfig()
-logging.getLogger("Slither").setLevel(logging.INFO)
-logging.getLogger("Printers").setLevel(logging.INFO)
-
-
-class PrinterCallGraphStateChange(PrinterCallGraph):
-    def _process_function(
-        self,
-        contract,
-        function,
-        contract_functions,
-        contract_calls,
-        solidity_functions,
-        solidity_calls,
-        external_calls,
-        all_contracts,
-    ):
-        if function.view or function.pure:
-            return
-        super()._process_function(
-            contract,
-            function,
-            contract_functions,
-            contract_calls,
-            solidity_functions,
-            solidity_calls,
-            external_calls,
-            all_contracts,
-        )
-
-    def _process_internal_call(
-        self, contract, function, internal_call, contract_calls, solidity_functions, solidity_calls
-    ):
-        if isinstance(internal_call, Function):
-            if internal_call.view or internal_call.pure:
-                return
-        super()._process_internal_call(
-            contract, function, internal_call, contract_calls, solidity_functions, solidity_calls
-        )
-
-    def _process_external_call(
-        self, contract, function, external_call, contract_functions, external_calls, all_contracts
-    ):
-        if isinstance(external_call[1], Function):
-            if external_call[1].view or external_call[1].pure:
-                return
-        super()._process_external_call(
-            contract, function, external_call, contract_functions, external_calls, all_contracts
-        )
-
-
-def parse_args():
-    """
-    """
-    parser = argparse.ArgumentParser(
-        description="Call graph printer. Similar to --print call-graph, but without printing the view/pure functions",
-        usage="call_graph.py filename",
-    )
-
-    parser.add_argument(
-        "filename", help="The filename of the contract or truffle directory to analyze."
-    )
-
-    parser.add_argument("--solc", help="solc path", default="solc")
-
-    return parser.parse_args()
-
-
-def main():
-
-    args = parse_args()
-    slither = Slither(args.filename, is_truffle=os.path.isdir(args.filename), solc=args.solc)
-
-    slither.register_printer(PrinterCallGraphStateChange)
-
-    slither.run_printers()
-
-
-if __name__ == "__main__":
-    main()

+ 0 - 39
examples/scripts/convert_to_evm_ins.py

@@ -1,39 +0,0 @@
-import sys
-from slither.slither import Slither
-from slither.evm.convert import SourceToEVM
-
-if len(sys.argv) != 2:
-    print("python3 function_called.py functions_called.sol")
-    exit(-1)
-
-# Init slither
-slither = Slither(sys.argv[1])
-
-# Get the contract evm instructions
-contract = slither.get_contract_from_name("Test")
-contract_ins = SourceToEVM.get_evm_instructions(contract)
-print("## Contract evm instructions: {} ##".format(contract.name))
-for ins in contract_ins:
-    print(str(ins))
-
-# Get the constructor evm instructions
-constructor = contract.constructor
-print("## Function evm instructions: {} ##".format(constructor.name))
-constructor_ins = SourceToEVM.get_evm_instructions(constructor)
-for ins in constructor_ins:
-    print(str(ins))
-
-# Get the function evm instructions
-function = contract.get_function_from_signature("foo()")
-print("## Function evm instructions: {} ##".format(function.name))
-function_ins = SourceToEVM.get_evm_instructions(function)
-for ins in function_ins:
-    print(str(ins))
-
-# Get the node evm instructions
-nodes = function.nodes
-for node in nodes:
-    node_ins = SourceToEVM.get_evm_instructions(node)
-    print("Node evm instructions: {}".format(str(node)))
-    for ins in node_ins:
-        print(str(ins))

+ 2 - 2
examples/scripts/convert_to_ir.py

@@ -5,7 +5,7 @@ from slither.slithir.convert import convert_expression
 
 if len(sys.argv) != 2:
     print("python function_called.py functions_called.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])
@@ -21,7 +21,7 @@ nodes = test.nodes
 for node in nodes:
     if node.expression:
         print("Expression:\n\t{}".format(node.expression))
-        irs = convert_expression(node.expression)
+        irs = convert_expression(node.expression, node)
         print("IR expressions:")
         for ir in irs:
             print("\t{}".format(ir))

+ 2 - 2
examples/scripts/data_dependency.py

@@ -1,15 +1,15 @@
 import sys
+
 from slither import Slither
 from slither.analyses.data_dependency.data_dependency import (
     is_dependent,
     is_tainted,
-    pprint_dependency,
 )
 from slither.core.declarations.solidity_variables import SolidityVariableComposed
 
 if len(sys.argv) != 2:
     print("Usage: python data_dependency.py file.sol")
-    exit(-1)
+    sys.exit(-1)
 
 slither = Slither(sys.argv[1])
 

+ 1 - 1
examples/scripts/export_dominator_tree_to_dot.py

@@ -4,7 +4,7 @@ from slither.slither import Slither
 
 if len(sys.argv) != 2:
     print("python export_dominator_tree_to_dot.py contract.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])

+ 1 - 1
examples/scripts/export_to_dot.py

@@ -4,7 +4,7 @@ from slither.slither import Slither
 
 if len(sys.argv) != 2:
     print("python function_called.py contract.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])

+ 1 - 1
examples/scripts/functions_called.py

@@ -3,7 +3,7 @@ from slither.slither import Slither
 
 if len(sys.argv) != 2:
     print("python functions_called.py functions_called.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])

+ 1 - 1
examples/scripts/functions_writing.py

@@ -3,7 +3,7 @@ from slither.slither import Slither
 
 if len(sys.argv) != 2:
     print("python function_writing.py functions_writing.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])

+ 6 - 6
examples/scripts/possible_paths.py

@@ -84,8 +84,8 @@ def all_function_definitions(function):
     ]
 
 
-def __find_target_paths(target_function, current_path=[]):
-
+def __find_target_paths(target_function, current_path=None):
+    current_path = current_path if current_path else []
     # Create our results list
     results = set()
 
@@ -184,17 +184,17 @@ slither = Slither(args.filename, is_truffle=args.is_truffle)
 targets = resolve_functions(args.targets)
 
 # Print out all target functions.
-print(f"Target functions:")
+print("Target functions:")
 for target in targets:
     print(f"-{target.contract.name}.{target.full_name}")
 print("\n")
 
 # Obtain all paths which reach the target functions.
 reaching_paths = find_target_paths(targets)
-reaching_functions = set([y for x in reaching_paths for y in x if y not in targets])
+reaching_functions = {y for x in reaching_paths for y in x if y not in targets}
 
 # Print out all function names which can reach the targets.
-print(f"The following functions reach the specified targets:")
+print("The following functions reach the specified targets:")
 for function_desc in sorted([f"{f.canonical_name}" for f in reaching_functions]):
     print(f"-{function_desc}")
 print("\n")
@@ -205,6 +205,6 @@ reaching_paths_str = [
 ]
 
 # Print a sorted list of all function paths which can reach the targets.
-print(f"The following paths reach the specified targets:")
+print("The following paths reach the specified targets:")
 for reaching_path in sorted(reaching_paths_str):
     print(f"{reaching_path}\n")

+ 1 - 1
examples/scripts/slithIR.py

@@ -3,7 +3,7 @@ from slither import Slither
 
 if len(sys.argv) != 2:
     print("python slithIR.py contract.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])

+ 4 - 4
examples/scripts/taint_mapping.py

@@ -58,7 +58,7 @@ def check_call(func, taints):
 if __name__ == "__main__":
     if len(sys.argv) != 2:
         print("python taint_mapping.py taint.sol")
-        exit(-1)
+        sys.exit(-1)
 
     # Init slither
     slither = Slither(sys.argv[1])
@@ -79,11 +79,11 @@ if __name__ == "__main__":
                 visit_node(function.entry_point, [])
                 print("All variables tainted : {}".format([str(v) for v in slither.context[KEY]]))
 
+            for function in contract.functions:
+                check_call(function, slither.context[KEY])
+
     print(
         "All state variables tainted : {}".format(
             [str(v) for v in prev_taints if isinstance(v, StateVariable)]
         )
     )
-
-    for function in contract.functions:
-        check_call(function, slither.context[KEY])

+ 1 - 1
examples/scripts/variable_in_condition.py

@@ -3,7 +3,7 @@ from slither.slither import Slither
 
 if len(sys.argv) != 2:
     print("python variable_in_condition.py variable_in_condition.sol")
-    exit(-1)
+    sys.exit(-1)
 
 # Init slither
 slither = Slither(sys.argv[1])

+ 8 - 1
pyproject.toml

@@ -9,5 +9,12 @@ missing-function-docstring,
 unnecessary-lambda,
 bad-continuation,
 cyclic-import,
-line-too-long
+line-too-long,
+invalid-name,
+fixme,
+too-many-return-statements,
+too-many-ancestors,
+logging-fstring-interpolation,
+logging-not-lazy,
+duplicate-code
 """

+ 3 - 2
scripts/json_diff.py

@@ -1,11 +1,12 @@
 import sys
 import json
-from deepdiff import DeepDiff  # pip install deepdiff
 from pprint import pprint
+from deepdiff import DeepDiff  # pip install deepdiff
+
 
 if len(sys.argv) != 3:
     print("Usage: python json_diff.py 1.json 2.json")
-    exit(-1)
+    sys.exit(-1)
 
 with open(sys.argv[1], encoding="utf8") as f:
     d1 = json.load(f)

+ 111 - 62
slither/__main__.py

@@ -10,8 +10,10 @@ import sys
 import traceback
 
 from pkg_resources import iter_entry_points, require
+
 from crytic_compile import cryticparser
 from crytic_compile.platform.standard import generate_standard_export
+from crytic_compile import compile_all, is_supported
 
 from slither.detectors import all_detectors
 from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
@@ -34,7 +36,6 @@ from slither.utils.command_line import (
     JSON_OUTPUT_TYPES,
     DEFAULT_JSON_OUTPUT_TYPES,
 )
-from crytic_compile import compile_all, is_supported
 from slither.exceptions import SlitherException
 
 logging.basicConfig()
@@ -80,7 +81,12 @@ def process_all(target, args, detector_classes, printer_classes):
         results_printers.extend(current_results_printers)
         slither_instances.append(slither)
         analyzed_contracts_count += current_analyzed_count
-    return slither_instances, results_detectors, results_printers, analyzed_contracts_count
+    return (
+        slither_instances,
+        results_detectors,
+        results_printers,
+        analyzed_contracts_count,
+    )
 
 
 def _process(slither, detector_classes, printer_classes):
@@ -98,7 +104,9 @@ def _process(slither, detector_classes, printer_classes):
     if not printer_classes:
         detector_results = slither.run_detectors()
         detector_results = [x for x in detector_results if x]  # remove empty results
-        detector_results = [item for sublist in detector_results for item in sublist]  # flatten
+        detector_results = [
+            item for sublist in detector_results for item in sublist
+        ]  # flatten
         results_detectors.extend(detector_results)
 
     else:
@@ -113,8 +121,8 @@ def process_from_asts(filenames, args, detector_classes, printer_classes):
     all_contracts = []
 
     for filename in filenames:
-        with open(filename, encoding="utf8") as f:
-            contract_loaded = json.load(f)
+        with open(filename, encoding="utf8") as file_open:
+            contract_loaded = json.load(file_open)
             all_contracts.append(contract_loaded["ast"])
 
     return process_single(all_contracts, args, detector_classes, printer_classes)
@@ -128,7 +136,7 @@ def process_from_asts(filenames, args, detector_classes, printer_classes):
 ###################################################################################
 
 
-def exit(results):
+def my_exit(results):
     if not results:
         sys.exit(0)
     sys.exit(len(results))
@@ -148,10 +156,14 @@ def get_detectors_and_printers():
     """
 
     detectors = [getattr(all_detectors, name) for name in dir(all_detectors)]
-    detectors = [d for d in detectors if inspect.isclass(d) and issubclass(d, AbstractDetector)]
+    detectors = [
+        d for d in detectors if inspect.isclass(d) and issubclass(d, AbstractDetector)
+    ]
 
     printers = [getattr(all_printers, name) for name in dir(all_printers)]
-    printers = [p for p in printers if inspect.isclass(p) and issubclass(p, AbstractPrinter)]
+    printers = [
+        p for p in printers if inspect.isclass(p) and issubclass(p, AbstractPrinter)
+    ]
 
     # Handle plugins!
     for entry_point in iter_entry_points(group="slither_analyzer.plugin", name=None):
@@ -159,11 +171,16 @@ def get_detectors_and_printers():
 
         plugin_detectors, plugin_printers = make_plugin()
 
-        if not all(issubclass(d, AbstractDetector) for d in plugin_detectors):
-            raise Exception("Error when loading plugin %s, %r is not a detector" % (entry_point, d))
-
-        if not all(issubclass(p, AbstractPrinter) for p in plugin_printers):
-            raise Exception("Error when loading plugin %s, %r is not a printer" % (entry_point, p))
+        detector = None
+        if not all(issubclass(detector, AbstractDetector) for detector in plugin_detectors):
+            raise Exception(
+                "Error when loading plugin %s, %r is not a detector" % (entry_point, detector)
+            )
+        printer = None
+        if not all(issubclass(printer, AbstractPrinter) for printer in plugin_printers):
+            raise Exception(
+                "Error when loading plugin %s, %r is not a printer" % (entry_point, printer)
+            )
 
         # We convert those to lists in case someone returns a tuple
         detectors += list(plugin_detectors)
@@ -171,7 +188,7 @@ def get_detectors_and_printers():
 
     return detectors, printers
 
-
+# pylint: disable=too-many-branches
 def choose_detectors(args, all_detector_classes):
     # If detectors are specified, run only these ones
 
@@ -182,35 +199,43 @@ def choose_detectors(args, all_detector_classes):
         detectors_to_run = all_detector_classes
         if args.detectors_to_exclude:
             detectors_excluded = args.detectors_to_exclude.split(",")
-            for d in detectors:
-                if d in detectors_excluded:
-                    detectors_to_run.remove(detectors[d])
+            for detector in detectors:
+                if detector in detectors_excluded:
+                    detectors_to_run.remove(detectors[detector])
     else:
-        for d in args.detectors_to_run.split(","):
-            if d in detectors:
-                detectors_to_run.append(detectors[d])
+        for detector in args.detectors_to_run.split(","):
+            if detector in detectors:
+                detectors_to_run.append(detectors[detector])
             else:
-                raise Exception("Error: {} is not a detector".format(d))
+                raise Exception("Error: {} is not a detector".format(detector))
         detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT)
         return detectors_to_run
 
     if args.exclude_optimization:
         detectors_to_run = [
-            d for d in detectors_to_run if d.IMPACT != DetectorClassification.OPTIMIZATION
+            d
+            for d in detectors_to_run
+            if d.IMPACT != DetectorClassification.OPTIMIZATION
         ]
 
     if args.exclude_informational:
         detectors_to_run = [
-            d for d in detectors_to_run if d.IMPACT != DetectorClassification.INFORMATIONAL
+            d
+            for d in detectors_to_run
+            if d.IMPACT != DetectorClassification.INFORMATIONAL
         ]
     if args.exclude_low:
-        detectors_to_run = [d for d in detectors_to_run if d.IMPACT != DetectorClassification.LOW]
+        detectors_to_run = [
+            d for d in detectors_to_run if d.IMPACT != DetectorClassification.LOW
+        ]
     if args.exclude_medium:
         detectors_to_run = [
             d for d in detectors_to_run if d.IMPACT != DetectorClassification.MEDIUM
         ]
     if args.exclude_high:
-        detectors_to_run = [d for d in detectors_to_run if d.IMPACT != DetectorClassification.HIGH]
+        detectors_to_run = [
+            d for d in detectors_to_run if d.IMPACT != DetectorClassification.HIGH
+        ]
     if args.detectors_to_exclude:
         detectors_to_run = [
             d for d in detectors_to_run if d.ARGUMENT not in args.detectors_to_exclude
@@ -232,11 +257,11 @@ def choose_printers(args, all_printer_classes):
         return all_printer_classes
 
     printers = {p.ARGUMENT: p for p in all_printer_classes}
-    for p in args.printers_to_run.split(","):
-        if p in printers:
-            printers_to_run.append(printers[p])
+    for printer in args.printers_to_run.split(","):
+        if printer in printers:
+            printers_to_run.append(printers[printer])
         else:
-            raise Exception("Error: {} is not a printer".format(p))
+            raise Exception("Error: {} is not a printer".format(printer))
     return printers_to_run
 
 
@@ -278,7 +303,9 @@ def parse_args(detector_classes, printer_classes):
     group_detector.add_argument(
         "--detect",
         help="Comma-separated list of detectors, defaults to all, "
-        "available detectors: {}".format(", ".join(d.ARGUMENT for d in detector_classes)),
+             "available detectors: {}".format(
+            ", ".join(d.ARGUMENT for d in detector_classes)
+        ),
         action="store",
         dest="detectors_to_run",
         default=defaults_flag_in_config["detectors_to_run"],
@@ -287,7 +314,7 @@ def parse_args(detector_classes, printer_classes):
     group_printer.add_argument(
         "--print",
         help="Comma-separated list fo contract information printers, "
-        "available printers: {}".format(", ".join(d.ARGUMENT for d in printer_classes)),
+             "available printers: {}".format(", ".join(d.ARGUMENT for d in printer_classes)),
         action="store",
         dest="printers_to_run",
         default=defaults_flag_in_config["printers_to_run"],
@@ -368,9 +395,9 @@ def parse_args(detector_classes, printer_classes):
 
     group_misc.add_argument(
         "--json-types",
-        help=f"Comma-separated list of result types to output to JSON, defaults to "
-        + f'{",".join(output_type for output_type in DEFAULT_JSON_OUTPUT_TYPES)}. '
-        + f'Available types: {",".join(output_type for output_type in JSON_OUTPUT_TYPES)}',
+        help="Comma-separated list of result types to output to JSON, defaults to "
+             + f'{",".join(output_type for output_type in DEFAULT_JSON_OUTPUT_TYPES)}. '
+             + f'Available types: {",".join(output_type for output_type in JSON_OUTPUT_TYPES)}',
         action="store",
         default=defaults_flag_in_config["json-types"],
     )
@@ -390,7 +417,10 @@ def parse_args(detector_classes, printer_classes):
     )
 
     group_misc.add_argument(
-        "--markdown-root", help="URL for markdown generation", action="store", default=""
+        "--markdown-root",
+        help="URL for markdown generation",
+        action="store",
+        default="",
     )
 
     group_misc.add_argument(
@@ -425,7 +455,10 @@ def parse_args(detector_classes, printer_classes):
     )
 
     group_misc.add_argument(
-        "--solc-ast", help="Provide the contract as a json AST", action="store_true", default=False
+        "--solc-ast",
+        help="Provide the contract as a json AST",
+        action="store_true",
+        default=False,
     )
 
     group_misc.add_argument(
@@ -436,9 +469,13 @@ def parse_args(detector_classes, printer_classes):
     )
 
     # debugger command
-    parser.add_argument("--debug", help=argparse.SUPPRESS, action="store_true", default=False)
+    parser.add_argument(
+        "--debug", help=argparse.SUPPRESS, action="store_true", default=False
+    )
 
-    parser.add_argument("--markdown", help=argparse.SUPPRESS, action=OutputMarkdown, default=False)
+    parser.add_argument(
+        "--markdown", help=argparse.SUPPRESS, action=OutputMarkdown, default=False
+    )
 
     group_misc.add_argument(
         "--checklist", help=argparse.SUPPRESS, action="store_true", default=False
@@ -471,7 +508,9 @@ def parse_args(detector_classes, printer_classes):
     )
 
     # if the json is splitted in different files
-    parser.add_argument("--splitted", help=argparse.SUPPRESS, action="store_true", default=False)
+    parser.add_argument(
+        "--splitted", help=argparse.SUPPRESS, action="store_true", default=False
+    )
 
     # Disable the throw/catch on partial analyses
     parser.add_argument(
@@ -491,41 +530,43 @@ def parse_args(detector_classes, printer_classes):
     args.json_types = set(args.json_types.split(","))
     for json_type in args.json_types:
         if json_type not in JSON_OUTPUT_TYPES:
-            raise Exception(f'Error: "{json_type}" is not a valid JSON result output type.')
+            raise Exception(
+                f'Error: "{json_type}" is not a valid JSON result output type.'
+            )
 
     return args
 
 
-class ListDetectors(argparse.Action):
-    def __call__(self, parser, *args, **kwargs):
+class ListDetectors(argparse.Action):  # pylint: disable=too-few-public-methods
+    def __call__(self, parser, *args, **kwargs):  # pylint: disable=signature-differs
         detectors, _ = get_detectors_and_printers()
         output_detectors(detectors)
         parser.exit()
 
 
-class ListDetectorsJson(argparse.Action):
-    def __call__(self, parser, *args, **kwargs):
+class ListDetectorsJson(argparse.Action):  # pylint: disable=too-few-public-methods
+    def __call__(self, parser, *args, **kwargs):   # pylint: disable=signature-differs
         detectors, _ = get_detectors_and_printers()
         detector_types_json = output_detectors_json(detectors)
         print(json.dumps(detector_types_json))
         parser.exit()
 
 
-class ListPrinters(argparse.Action):
-    def __call__(self, parser, *args, **kwargs):
+class ListPrinters(argparse.Action):  # pylint: disable=too-few-public-methods
+    def __call__(self, parser, *args, **kwargs):   # pylint: disable=signature-differs
         _, printers = get_detectors_and_printers()
         output_printers(printers)
         parser.exit()
 
 
-class OutputMarkdown(argparse.Action):
+class OutputMarkdown(argparse.Action):  # pylint: disable=too-few-public-methods
     def __call__(self, parser, args, values, option_string=None):
         detectors, printers = get_detectors_and_printers()
         output_to_markdown(detectors, printers, values)
         parser.exit()
 
 
-class OutputWiki(argparse.Action):
+class OutputWiki(argparse.Action):  # pylint: disable=too-few-public-methods
     def __call__(self, parser, args, values, option_string=None):
         detectors, _ = get_detectors_and_printers()
         output_wiki(detectors, values)
@@ -569,6 +610,7 @@ def main():
     main_impl(all_detector_classes=detectors, all_printer_classes=printers)
 
 
+# pylint: disable=too-many-statements,too-many-branches,too-many-locals
 def main_impl(all_detector_classes, all_printer_classes):
     """
     :param all_detector_classes: A list of all detectors that can be included/excluded.
@@ -588,9 +630,8 @@ def main_impl(all_detector_classes, all_printer_classes):
     outputting_json_stdout = args.json == "-"
     outputting_zip = args.zip is not None
     if args.zip_type not in ZIP_TYPES_ACCEPTED.keys():
-        logger.error(
-            f'Zip type not accepted, it must be one of {",".join(ZIP_TYPES_ACCEPTED.keys())}'
-        )
+        to_log = f'Zip type not accepted, it must be one of {",".join(ZIP_TYPES_ACCEPTED.keys())}'
+        logger.error(to_log)
 
     # If we are outputting JSON, capture all standard output. If we are outputting to stdout, we block typical stdout
     # output.
@@ -616,8 +657,8 @@ def main_impl(all_detector_classes, all_printer_classes):
         ("Printers", default_log),
         # ('CryticCompile', default_log)
     ]:
-        l = logging.getLogger(l_name)
-        l.setLevel(l_level)
+        logger_level = logging.getLogger(l_name)
+        logger_level.setLevel(l_level)
 
     console_handler = logging.StreamHandler()
     console_handler.setLevel(logging.INFO)
@@ -649,7 +690,9 @@ def main_impl(all_detector_classes, all_printer_classes):
                     results_detectors,
                     results_printers,
                     number_contracts,
-                ) = process_from_asts(filenames, args, detector_classes, printer_classes)
+                ) = process_from_asts(
+                    filenames, args, detector_classes, printer_classes
+                )
                 slither_instances.append(slither_instance)
             else:
                 for filename in filenames:
@@ -658,7 +701,9 @@ def main_impl(all_detector_classes, all_printer_classes):
                         results_detectors_tmp,
                         results_printers_tmp,
                         number_contracts_tmp,
-                    ) = process_single(filename, args, detector_classes, printer_classes)
+                    ) = process_single(
+                        filename, args, detector_classes, printer_classes
+                    )
                     number_contracts += number_contracts_tmp
                     results_detectors += results_detectors_tmp
                     results_printers += results_printers_tmp
@@ -728,17 +773,19 @@ def main_impl(all_detector_classes, all_printer_classes):
         if args.ignore_return_value:
             return
 
-    except SlitherException as se:
-        output_error = str(se)
+    except SlitherException as slither_exception:
+        output_error = str(slither_exception)
         traceback.print_exc()
         logging.error(red("Error:"))
         logging.error(red(output_error))
-        logging.error("Please report an issue to https://github.com/crytic/slither/issues")
+        logging.error(
+            "Please report an issue to https://github.com/crytic/slither/issues"
+        )
 
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         output_error = traceback.format_exc()
         logging.error(traceback.print_exc())
-        logging.error("Error in %s" % args.filename)
+        logging.error(f"Error in {args.filename}")  # pylint: disable=logging-fstring-interpolation
         logging.error(output_error)
 
     # If we are outputting JSON, capture the redirected output and disable the redirect to output the final JSON.
@@ -749,7 +796,9 @@ def main_impl(all_detector_classes, all_printer_classes):
                 "stderr": StandardOutputCapture.get_stderr_output(),
             }
         StandardOutputCapture.disable()
-        output_to_json(None if outputting_json_stdout else args.json, output_error, json_results)
+        output_to_json(
+            None if outputting_json_stdout else args.json, output_error, json_results
+        )
 
     if outputting_zip:
         output_to_zip(args.zip, output_error, json_results, args.zip_type)
@@ -758,7 +807,7 @@ def main_impl(all_detector_classes, all_printer_classes):
     if output_error:
         sys.exit(-1)
     else:
-        exit(results_detectors)
+        my_exit(results_detectors)
 
 
 if __name__ == "__main__":

+ 1 - 0
slither/all_exceptions.py

@@ -1,6 +1,7 @@
 """
 This module import all slither exceptions
 """
+# pylint: disable=unused-import
 from slither.slithir.exceptions import SlithIRError
 from slither.solc_parsing.exceptions import ParsingError, VariableNotFound
 from slither.core.exceptions import SlitherCoreError

+ 37 - 10
slither/analyses/data_dependency/data_dependency.py

@@ -112,7 +112,9 @@ def is_tainted(variable, context, only_unprotected=False, ignore_generic_taint=F
     )
 
 
-def is_tainted_ssa(variable, context, only_unprotected=False, ignore_generic_taint=False):
+def is_tainted_ssa(
+    variable, context, only_unprotected=False, ignore_generic_taint=False
+):
     """
     Args:
         variable
@@ -135,7 +137,9 @@ def is_tainted_ssa(variable, context, only_unprotected=False, ignore_generic_tai
 
 
 def get_dependencies(
-    variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False
+    variable: Variable,
+    context: Union[Contract, Function],
+    only_unprotected: bool = False,
 ) -> Set[Variable]:
     """
     Return the variables for which `variable` depends on.
@@ -170,7 +174,9 @@ def get_all_dependencies(
 
 
 def get_dependencies_ssa(
-    variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False
+    variable: Variable,
+    context: Union[Contract, Function],
+    only_unprotected: bool = False,
 ) -> Set[Variable]:
     """
     Return the variables for which `variable` depends on (SSA version).
@@ -272,8 +278,11 @@ def compute_dependency_contract(contract, slither):
         compute_dependency_function(function)
 
         propagate_function(contract, function, KEY_SSA, KEY_NON_SSA)
-        propagate_function(contract, function, KEY_SSA_UNPROTECTED, KEY_NON_SSA_UNPROTECTED)
+        propagate_function(
+            contract, function, KEY_SSA_UNPROTECTED, KEY_NON_SSA_UNPROTECTED
+        )
 
+        # pylint: disable=expression-not-assigned
         if function.visibility in ["public", "external"]:
             [slither.context[KEY_INPUT].add(p) for p in function.parameters]
             [slither.context[KEY_INPUT_SSA].add(p) for p in function.parameters_ssa]
@@ -296,11 +305,12 @@ def propagate_function(contract, function, context_key, context_key_non_ssa):
 def transitive_close_dependencies(context, context_key, context_key_non_ssa):
     # transitive closure
     changed = True
-    while changed:
+    while changed:  # pylint: disable=too-many-nested-blocks
         changed = False
         # Need to create new set() as its changed during iteration
         data_depencencies = {
-            k: set([v for v in values]) for k, values in context.context[context_key].items()
+            k: set(values)
+            for k, values in context.context[context_key].items()
         }
         for key, items in data_depencencies.items():
             for item in items:
@@ -310,7 +320,9 @@ def transitive_close_dependencies(context, context_key, context_key_non_ssa):
                         if not additional_item in items and additional_item != key:
                             changed = True
                             context.context[context_key][key].add(additional_item)
-    context.context[context_key_non_ssa] = convert_to_non_ssa(context.context[context_key])
+    context.context[context_key_non_ssa] = convert_to_non_ssa(
+        context.context[context_key]
+    )
 
 
 def propagate_contract(contract, context_key, context_key_non_ssa):
@@ -328,7 +340,12 @@ def add_dependency(lvalue, function, ir, is_protected):
         read = ir.function.return_values_ssa
     else:
         read = ir.read
-    [function.context[KEY_SSA][lvalue].add(v) for v in read if not isinstance(v, Constant)]
+    # pylint: disable=expression-not-assigned
+    [
+        function.context[KEY_SSA][lvalue].add(v)
+        for v in read
+        if not isinstance(v, Constant)
+    ]
     if not is_protected:
         [
             function.context[KEY_SSA_UNPROTECTED][lvalue].add(v)
@@ -375,7 +392,17 @@ def convert_variable_to_non_ssa(v):
     ):
         return v.non_ssa_version
     assert isinstance(
-        v, (Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type)
+        v,
+        (
+            Constant,
+            SolidityVariable,
+            Contract,
+            Enum,
+            SolidityFunction,
+            Structure,
+            Function,
+            Type,
+        ),
     )
     return v
 
@@ -387,6 +414,6 @@ def convert_to_non_ssa(data_depencies):
         var = convert_variable_to_non_ssa(k)
         if not var in ret:
             ret[var] = set()
-        ret[var] = ret[var].union(set([convert_variable_to_non_ssa(v) for v in values]))
+        ret[var] = ret[var].union({convert_variable_to_non_ssa(v) for v in values})
 
     return ret

+ 24 - 13
slither/analyses/evm/convert.py

@@ -3,7 +3,7 @@ from slither.core.declarations import Contract, Function
 from slither.core.cfg.node import Node
 from slither.utils.function import get_function_id
 from slither.exceptions import SlitherError
-from .evm_cfg_builder import load_evm_cfg_builder
+from slither.analyses.evm.evm_cfg_builder import load_evm_cfg_builder
 
 logger = logging.getLogger("ConvertToEVM")
 
@@ -101,16 +101,17 @@ def _get_evm_instructions_function(function_info):
         # Todo: Could rename it appropriately in evm-cfg-builder
         #    by detecting that init bytecode is being parsed.
         name = "_dispatcher"
-        hash = ""
+        func_hash = ""
     else:
         cfg = function_info["contract_info"]["cfg"]
         name = function.name
         # Get first four bytes of function singature's keccak-256 hash used as function selector
-        hash = str(hex(get_function_id(function.full_name)))
+        func_hash = str(hex(get_function_id(function.full_name)))
 
-    function_evm = _get_function_evm(cfg, name, hash)
+    function_evm = _get_function_evm(cfg, name, func_hash)
     if function_evm is None:
-        logger.error("Function " + function.name + " not found in the EVM code")
+        to_log = "Function " + function.name + " not found in the EVM code"
+        logger.error(to_log)
         raise SlitherError("Function " + function.name + " not found in the EVM code")
 
     function_ins = []
@@ -137,7 +138,10 @@ def _get_evm_instructions_node(node_info):
 
     # Get evm instructions corresponding to node's source line number
     node_source_line = (
-        contract_file[0 : node_info["node"].source_mapping["start"]].count("\n".encode("utf-8")) + 1
+        contract_file[0 : node_info["node"].source_mapping["start"]].count(
+            "\n".encode("utf-8")
+        )
+        + 1
     )
     node_pcs = contract_pcs.get(node_source_line, [])
     node_ins = []
@@ -153,14 +157,19 @@ def _get_function_evm(cfg, function_name, function_hash):
         if function_evm.name[:2] == "0x" and function_evm.name == function_hash:
             return function_evm
         # Match function name
-        elif function_evm.name[:2] != "0x" and function_evm.name.split("(")[0] == function_name:
+        if (
+            function_evm.name[:2] != "0x"
+            and function_evm.name.split("(")[0] == function_name
+        ):
             return function_evm
     return None
 
-
-def generate_source_to_evm_ins_mapping(evm_instructions, srcmap_runtime, slither, filename):
+# pylint: disable=too-many-locals
+def generate_source_to_evm_ins_mapping(
+    evm_instructions, srcmap_runtime, slither, filename
+):
     """
-    Generate Solidity source to EVM instruction mapping using evm_cfg_builder:cfg.instructions 
+    Generate Solidity source to EVM instruction mapping using evm_cfg_builder:cfg.instructions
     and solc:srcmap_runtime
 
     Returns: Solidity source to EVM instruction mapping
@@ -180,11 +189,11 @@ def generate_source_to_evm_ins_mapping(evm_instructions, srcmap_runtime, slither
         mapping_item = mapping.split(":")
         mapping_item += prev_mapping[len(mapping_item) :]
 
-        for i in range(len(mapping_item)):
+        for i, _ in enumerate(mapping_item):
             if mapping_item[i] == "":
                 mapping_item[i] = int(prev_mapping[i])
 
-        offset, length, file_id, _ = mapping_item
+        offset, _length, file_id, _ = mapping_item
         prev_mapping = mapping_item
 
         if file_id == "-1":
@@ -198,6 +207,8 @@ def generate_source_to_evm_ins_mapping(evm_instructions, srcmap_runtime, slither
         # Append evm instructions to the corresponding source line number
         # Note: Some evm instructions in mapping are not necessarily in program execution order
         # Note: The order depends on how solc creates the srcmap_runtime
-        source_to_evm_mapping.setdefault(line_number, []).append(evm_instructions[idx].pc)
+        source_to_evm_mapping.setdefault(line_number, []).append(
+            evm_instructions[idx].pc
+        )
 
     return source_to_evm_mapping

+ 1 - 0
slither/analyses/evm/evm_cfg_builder.py

@@ -7,6 +7,7 @@ logger = logging.getLogger("ConvertToEVM")
 def load_evm_cfg_builder():
     try:
         # Avoiding the addition of evm_cfg_builder as permanent dependency
+        # pylint: disable=import-outside-toplevel
         from evm_cfg_builder.cfg import CFG
 
         return CFG

+ 14 - 5
slither/analyses/write/are_variables_written.py

@@ -2,7 +2,7 @@
     Detect if all the given variables are written in all the paths of the function
 """
 from collections import defaultdict
-from typing import Dict, Tuple, Set, List, Optional
+from typing import Dict, Set, List
 
 from slither.core.cfg.node import NodeType, Node
 from slither.core.declarations import SolidityFunction
@@ -18,7 +18,7 @@ from slither.slithir.operations import (
 from slither.slithir.variables import ReferenceVariable, TemporaryVariable
 
 
-class State:
+class State:  # pylint: disable=too-few-public-methods
     def __init__(self):
         # Map node -> list of variables set
         # Were each variables set represents a configuration of a path
@@ -33,8 +33,12 @@ class State:
         self.nodes: Dict[Node, List[Set[Variable]]] = defaultdict(list)
 
 
+# pylint: disable=too-many-branches
 def _visit(
-    node: Node, state: State, variables_written: Set[Variable], variables_to_write: List[Variable]
+    node: Node,
+    state: State,
+    variables_written: Set[Variable],
+    variables_to_write: List[Variable],
 ):
     """
     Explore all the nodes to look for values not written when the node's function return
@@ -51,7 +55,10 @@ def _visit(
     for ir in node.irs:
         if isinstance(ir, SolidityCall):
             # TODO convert the revert to a THROW node
-            if ir.function in [SolidityFunction("revert(string)"), SolidityFunction("revert()")]:
+            if ir.function in [
+                SolidityFunction("revert(string)"),
+                SolidityFunction("revert()"),
+            ]:
                 return []
 
         if not isinstance(ir, OperationWithLValue):
@@ -61,7 +68,9 @@ def _visit(
         if isinstance(ir, (Length, Balance)):
             refs[ir.lvalue] = ir.value
 
-        if ir.lvalue and not isinstance(ir.lvalue, (TemporaryVariable, ReferenceVariable)):
+        if ir.lvalue and not isinstance(
+            ir.lvalue, (TemporaryVariable, ReferenceVariable)
+        ):
             variables_written.add(ir.lvalue)
 
         lvalue = ir.lvalue

+ 69 - 27
slither/core/cfg/node.py

@@ -56,6 +56,8 @@ if TYPE_CHECKING:
     )
 
 
+# pylint: disable=too-many-lines,too-many-branches,too-many-instance-attributes
+
 ###################################################################################
 ###################################################################################
 # region NodeType
@@ -140,8 +142,9 @@ class NodeType(Enum):
 
 # endregion
 
-
-class Node(SourceMapping, ChildFunction):
+# I am not sure why, but pylint reports a lot of "no-member" issue that are not real (Josselin)
+# pylint: disable=no-member
+class Node(SourceMapping, ChildFunction):  # pylint: disable=too-many-public-methods
     """
     Node class
 
@@ -166,8 +169,12 @@ class Node(SourceMapping, ChildFunction):
         self._dominance_frontier: Set["Node"] = set()
         # Phi origin
         # key are variable name
-        self._phi_origins_state_variables: Dict[str, Tuple[StateVariable, Set["Node"]]] = {}
-        self._phi_origins_local_variables: Dict[str, Tuple[LocalVariable, Set["Node"]]] = {}
+        self._phi_origins_state_variables: Dict[
+            str, Tuple[StateVariable, Set["Node"]]
+        ] = {}
+        self._phi_origins_local_variables: Dict[
+            str, Tuple[LocalVariable, Set["Node"]]
+        ] = {}
         # self._phi_origins_member_variables: Dict[str, Tuple[MemberVariable, Set["Node"]]] = {}
 
         self._expression: Optional[Expression] = None
@@ -180,7 +187,7 @@ class Node(SourceMapping, ChildFunction):
         self._ssa_vars_written: List["SlithIRVariable"] = []
         self._ssa_vars_read: List["SlithIRVariable"] = []
 
-        self._internal_calls: List[Function] = []
+        self._internal_calls: List["Function"] = []
         self._solidity_calls: List[SolidityFunction] = []
         self._high_level_calls: List["HighLevelCallType"] = []  # contains library calls
         self._library_calls: List["LibraryCallType"] = []
@@ -457,6 +464,7 @@ class Node(SourceMapping, ChildFunction):
         :param callstack: used internally to check for recursion
         :return bool:
         """
+        # pylint: disable=import-outside-toplevel
         from slither.slithir.operations import Call
 
         if self._can_reenter is None:
@@ -472,6 +480,7 @@ class Node(SourceMapping, ChildFunction):
         Check if the node can send eth
         :return bool:
         """
+        # pylint: disable=import-outside-toplevel
         from slither.slithir.operations import Call
 
         if self._can_send_eth is None:
@@ -712,7 +721,9 @@ class Node(SourceMapping, ChildFunction):
 
     @staticmethod
     def _is_non_slithir_var(var: Variable):
-        return not isinstance(var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable))
+        return not isinstance(
+            var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable)
+        )
 
     @staticmethod
     def _is_valid_slithir_var(var: Variable):
@@ -793,11 +804,15 @@ class Node(SourceMapping, ChildFunction):
     ###################################################################################
 
     @property
-    def phi_origins_local_variables(self) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]:
+    def phi_origins_local_variables(
+        self,
+    ) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]:
         return self._phi_origins_local_variables
 
     @property
-    def phi_origins_state_variables(self) -> Dict[str, Tuple[StateVariable, Set["Node"]]]:
+    def phi_origins_state_variables(
+        self,
+    ) -> Dict[str, Tuple[StateVariable, Set["Node"]]]:
         return self._phi_origins_state_variables
 
     # @property
@@ -835,11 +850,12 @@ class Node(SourceMapping, ChildFunction):
     ###################################################################################
     ###################################################################################
 
-    def _find_read_write_call(self):
+    def _find_read_write_call(self):  # pylint: disable=too-many-statements
 
         for ir in self.irs:
 
-            self._slithir_vars |= set([v for v in ir.read if self._is_valid_slithir_var(v)])
+            self._slithir_vars |= {v for v in ir.read if self._is_valid_slithir_var(v)}
+
             if isinstance(ir, OperationWithLValue):
                 var = ir.lvalue
                 if var and self._is_valid_slithir_var(var):
@@ -884,7 +900,9 @@ class Node(SourceMapping, ChildFunction):
                     self._high_level_calls.append((self.function.contract, ir.function))
                 else:
                     try:
-                        self._high_level_calls.append((ir.destination.type.type, ir.function))
+                        self._high_level_calls.append(
+                            (ir.destination.type.type, ir.function)
+                        )
                     except AttributeError:
                         raise SlitherException(
                             f"Function not found on {ir}. Please try compiling with a recent Solidity version."
@@ -895,12 +913,22 @@ class Node(SourceMapping, ChildFunction):
                 self._library_calls.append((ir.destination, ir.function))
 
         self._vars_read = list(set(self._vars_read))
-        self._state_vars_read = [v for v in self._vars_read if isinstance(v, StateVariable)]
-        self._local_vars_read = [v for v in self._vars_read if isinstance(v, LocalVariable)]
-        self._solidity_vars_read = [v for v in self._vars_read if isinstance(v, SolidityVariable)]
+        self._state_vars_read = [
+            v for v in self._vars_read if isinstance(v, StateVariable)
+        ]
+        self._local_vars_read = [
+            v for v in self._vars_read if isinstance(v, LocalVariable)
+        ]
+        self._solidity_vars_read = [
+            v for v in self._vars_read if isinstance(v, SolidityVariable)
+        ]
         self._vars_written = list(set(self._vars_written))
-        self._state_vars_written = [v for v in self._vars_written if isinstance(v, StateVariable)]
-        self._local_vars_written = [v for v in self._vars_written if isinstance(v, LocalVariable)]
+        self._state_vars_written = [
+            v for v in self._vars_written if isinstance(v, StateVariable)
+        ]
+        self._local_vars_written = [
+            v for v in self._vars_written if isinstance(v, LocalVariable)
+        ]
         self._internal_calls = list(set(self._internal_calls))
         self._solidity_calls = list(set(self._solidity_calls))
         self._high_level_calls = list(set(self._high_level_calls))
@@ -926,7 +954,9 @@ class Node(SourceMapping, ChildFunction):
                 continue
             if not isinstance(ir, (Phi, Index, Member)):
                 self._ssa_vars_read += [
-                    v for v in ir.read if isinstance(v, (StateIRVariable, LocalIRVariable))
+                    v
+                    for v in ir.read
+                    if isinstance(v, (StateIRVariable, LocalIRVariable))
                 ]
                 for var in ir.read:
                     if isinstance(var, ReferenceVariable):
@@ -954,8 +984,12 @@ class Node(SourceMapping, ChildFunction):
                         continue
                     self._ssa_vars_written.append(var)
         self._ssa_vars_read = list(set(self._ssa_vars_read))
-        self._ssa_state_vars_read = [v for v in self._ssa_vars_read if isinstance(v, StateVariable)]
-        self._ssa_local_vars_read = [v for v in self._ssa_vars_read if isinstance(v, LocalVariable)]
+        self._ssa_state_vars_read = [
+            v for v in self._ssa_vars_read if isinstance(v, StateVariable)
+        ]
+        self._ssa_local_vars_read = [
+            v for v in self._ssa_vars_read if isinstance(v, LocalVariable)
+        ]
         self._ssa_vars_written = list(set(self._ssa_vars_written))
         self._ssa_state_vars_written = [
             v for v in self._ssa_vars_written if isinstance(v, StateVariable)
@@ -968,12 +1002,20 @@ class Node(SourceMapping, ChildFunction):
         vars_written = [self._convert_ssa(x) for x in self._ssa_vars_written]
 
         self._vars_read += [v for v in vars_read if v not in self._vars_read]
-        self._state_vars_read = [v for v in self._vars_read if isinstance(v, StateVariable)]
-        self._local_vars_read = [v for v in self._vars_read if isinstance(v, LocalVariable)]
+        self._state_vars_read = [
+            v for v in self._vars_read if isinstance(v, StateVariable)
+        ]
+        self._local_vars_read = [
+            v for v in self._vars_read if isinstance(v, LocalVariable)
+        ]
 
         self._vars_written += [v for v in vars_written if v not in self._vars_written]
-        self._state_vars_written = [v for v in self._vars_written if isinstance(v, StateVariable)]
-        self._local_vars_written = [v for v in self._vars_written if isinstance(v, LocalVariable)]
+        self._state_vars_written = [
+            v for v in self._vars_written if isinstance(v, StateVariable)
+        ]
+        self._local_vars_written = [
+            v for v in self._vars_written if isinstance(v, LocalVariable)
+        ]
 
     # endregion
     ###################################################################################
@@ -1024,11 +1066,11 @@ def recheable(node: Node) -> Set[Node]:
     nodes = node.sons
     visited = set()
     while nodes:
-        next = nodes[0]
+        next_node = nodes[0]
         nodes = nodes[1:]
-        if next not in visited:
-            visited.add(next)
-            for son in next.sons:
+        if next_node not in visited:
+            visited.add(next_node)
+            for son in next_node.sons:
                 if son not in visited:
                     nodes.append(son)
     return visited

+ 1 - 1
slither/core/children/child_node.py

@@ -6,7 +6,7 @@ if TYPE_CHECKING:
     from slither.core.declarations import Function, Contract
 
 
-class ChildNode(object):
+class ChildNode:
     def __init__(self):
         super(ChildNode, self).__init__()
         self._node = None

+ 1 - 1
slither/core/context/context.py

@@ -2,7 +2,7 @@ from collections import defaultdict
 from typing import Dict
 
 
-class Context:
+class Context:  # pylint: disable=too-few-public-methods
     def __init__(self):
         super(Context, self).__init__()
         self._context = {"MEMBERS": defaultdict(None)}

+ 5 - 1
slither/core/declarations/__init__.py

@@ -5,5 +5,9 @@ from .function import Function
 from .import_directive import Import
 from .modifier import Modifier
 from .pragma_directive import Pragma
-from .solidity_variables import SolidityVariable, SolidityVariableComposed, SolidityFunction
+from .solidity_variables import (
+    SolidityVariable,
+    SolidityVariableComposed,
+    SolidityFunction,
+)
 from .structure import Structure

+ 130 - 47
slither/core/declarations/contract.py

@@ -3,9 +3,9 @@
 """
 import logging
 from pathlib import Path
+from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union
 
 from crytic_compile.platform import Type as PlatformType
-from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union
 
 from slither.core.children.child_slither import ChildSlither
 from slither.core.solidity_types.type import Type
@@ -22,6 +22,7 @@ from slither.utils.erc import (
 )
 from slither.utils.tests_pattern import is_test_contract
 
+# pylint: disable=too-many-lines,too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks
 if TYPE_CHECKING:
     from slither.utils.type_helpers import LibraryCallType, HighLevelCallType
     from slither.core.declarations import Enum, Event, Modifier
@@ -33,7 +34,7 @@ if TYPE_CHECKING:
 LOGGER = logging.getLogger("Contract")
 
 
-class Contract(ChildSlither, SourceMapping):
+class Contract(ChildSlither, SourceMapping):   # pylint: disable=too-many-public-methods
     """
     Contract class
     """
@@ -43,7 +44,9 @@ class Contract(ChildSlither, SourceMapping):
 
         self._name: Optional[str] = None
         self._id: Optional[int] = None
-        self._inheritance: List["Contract"] = []  # all contract inherited, c3 linearization
+        self._inheritance: List[
+            "Contract"
+        ] = []  # all contract inherited, c3 linearization
         self._immediate_inheritance: List["Contract"] = []  # immediate inheritance
 
         # Constructors called on contract's definition
@@ -338,7 +341,11 @@ class Contract(ChildSlither, SourceMapping):
 
                             On "contract B is A(){..}" it returns the constructor of A
         """
-        return [c.constructor for c in self._explicit_base_constructor_calls if c.constructor]
+        return [
+            c.constructor
+            for c in self._explicit_base_constructor_calls
+            if c.constructor
+        ]
 
     # endregion
     ###################################################################################
@@ -355,12 +362,16 @@ class Contract(ChildSlither, SourceMapping):
         """
         if self._signatures is None:
             sigs = [
-                v.full_name for v in self.state_variables if v.visibility in ["public", "external"]
+                v.full_name
+                for v in self.state_variables
+                if v.visibility in ["public", "external"]
             ]
 
-            sigs += set(
-                [f.full_name for f in self.functions if f.visibility in ["public", "external"]]
-            )
+            sigs += {
+                f.full_name
+                for f in self.functions
+                if f.visibility in ["public", "external"]
+            }
             self._signatures = list(set(sigs))
         return self._signatures
 
@@ -377,13 +388,11 @@ class Contract(ChildSlither, SourceMapping):
                 if v.visibility in ["public", "external"]
             ]
 
-            sigs += set(
-                [
-                    f.full_name
-                    for f in self.functions_declared
-                    if f.visibility in ["public", "external"]
-                ]
-            )
+            sigs += {
+                f.full_name
+                for f in self.functions_declared
+                if f.visibility in ["public", "external"]
+            }
             self._signatures_declared = list(set(sigs))
         return self._signatures_declared
 
@@ -397,6 +406,9 @@ class Contract(ChildSlither, SourceMapping):
     def available_functions_as_dict(self) -> Dict[str, "Function"]:
         return {f.full_name: f for f in self._functions.values() if not f.is_shadowed}
 
+    def add_function(self, func: "Function"):
+        self._functions[func.canonical_name] = func
+
     def set_functions(self, functions: Dict[str, "Function"]):
         """
         Set the functions
@@ -569,19 +581,25 @@ class Contract(ChildSlither, SourceMapping):
     ###################################################################################
     ###################################################################################
 
-    def get_functions_reading_from_variable(self, variable: "Variable") -> List["Function"]:
+    def get_functions_reading_from_variable(
+        self, variable: "Variable"
+    ) -> List["Function"]:
         """
             Return the functions reading the variable
         """
         return [f for f in self.functions if f.is_reading(variable)]
 
-    def get_functions_writing_to_variable(self, variable: "Variable") -> List["Function"]:
+    def get_functions_writing_to_variable(
+        self, variable: "Variable"
+    ) -> List["Function"]:
         """
             Return the functions writting the variable
         """
         return [f for f in self.functions if f.is_writing(variable)]
 
-    def get_function_from_signature(self, function_signature: str) -> Optional["Function"]:
+    def get_function_from_signature(
+        self, function_signature: str
+    ) -> Optional["Function"]:
         """
             Return a function from a signature
         Args:
@@ -590,22 +608,34 @@ class Contract(ChildSlither, SourceMapping):
             Function
         """
         return next(
-            (f for f in self.functions if f.full_name == function_signature and not f.is_shadowed),
+            (
+                f
+                for f in self.functions
+                if f.full_name == function_signature and not f.is_shadowed
+            ),
             None,
         )
 
-    def get_modifier_from_signature(self, modifier_signature: str) -> Optional["Modifier"]:
+    def get_modifier_from_signature(
+        self, modifier_signature: str
+    ) -> Optional["Modifier"]:
         """
             Return a modifier from a signature
 
             :param modifier_signature:
         """
         return next(
-            (m for m in self.modifiers if m.full_name == modifier_signature and not m.is_shadowed),
+            (
+                m
+                for m in self.modifiers
+                if m.full_name == modifier_signature and not m.is_shadowed
+            ),
             None,
         )
 
-    def get_function_from_canonical_name(self, canonical_name: str) -> Optional["Function"]:
+    def get_function_from_canonical_name(
+        self, canonical_name: str
+    ) -> Optional["Function"]:
         """
             Return a function from a a canonical name (contract.signature())
         Args:
@@ -613,9 +643,13 @@ class Contract(ChildSlither, SourceMapping):
         Returns:
             Function
         """
-        return next((f for f in self.functions if f.canonical_name == canonical_name), None)
+        return next(
+            (f for f in self.functions if f.canonical_name == canonical_name), None
+        )
 
-    def get_modifier_from_canonical_name(self, canonical_name: str) -> Optional["Modifier"]:
+    def get_modifier_from_canonical_name(
+        self, canonical_name: str
+    ) -> Optional["Modifier"]:
         """
             Return a modifier from a canonical name (contract.signature())
         Args:
@@ -623,9 +657,13 @@ class Contract(ChildSlither, SourceMapping):
         Returns:
             Modifier
         """
-        return next((m for m in self.modifiers if m.canonical_name == canonical_name), None)
+        return next(
+            (m for m in self.modifiers if m.canonical_name == canonical_name), None
+        )
 
-    def get_state_variable_from_name(self, variable_name: str) -> Optional["StateVariable"]:
+    def get_state_variable_from_name(
+        self, variable_name: str
+    ) -> Optional["StateVariable"]:
         """
             Return a state variable from a name
 
@@ -655,7 +693,9 @@ class Contract(ChildSlither, SourceMapping):
         """
         return next((st for st in self.structures if st.name == structure_name), None)
 
-    def get_structure_from_canonical_name(self, structure_name: str) -> Optional["Structure"]:
+    def get_structure_from_canonical_name(
+        self, structure_name: str
+    ) -> Optional["Structure"]:
         """
             Return a structure from a canonical name
         Args:
@@ -663,7 +703,9 @@ class Contract(ChildSlither, SourceMapping):
         Returns:
             Structure
         """
-        return next((st for st in self.structures if st.canonical_name == structure_name), None)
+        return next(
+            (st for st in self.structures if st.canonical_name == structure_name), None
+        )
 
     def get_event_from_signature(self, event_signature: str) -> Optional["Event"]:
         """
@@ -675,7 +717,9 @@ class Contract(ChildSlither, SourceMapping):
         """
         return next((e for e in self.events if e.full_name == event_signature), None)
 
-    def get_event_from_canonical_name(self, event_canonical_name: str) -> Optional["Event"]:
+    def get_event_from_canonical_name(
+        self, event_canonical_name: str
+    ) -> Optional["Event"]:
         """
             Return an event from a canonical name
         Args:
@@ -683,7 +727,9 @@ class Contract(ChildSlither, SourceMapping):
         Returns:
             Event
         """
-        return next((e for e in self.events if e.canonical_name == event_canonical_name), None)
+        return next(
+            (e for e in self.events if e.canonical_name == event_canonical_name), None
+        )
 
     def get_enum_from_name(self, enum_name: str) -> Optional["Enum"]:
         """
@@ -775,7 +821,9 @@ class Contract(ChildSlither, SourceMapping):
             list((Contract, Function): List all of the libraries func called
         """
         all_high_level_calls = [f.all_library_calls() for f in self.functions + self.modifiers]  # type: ignore
-        all_high_level_calls = [item for sublist in all_high_level_calls for item in sublist]
+        all_high_level_calls = [
+            item for sublist in all_high_level_calls for item in sublist
+        ]
         return list(set(all_high_level_calls))
 
     @property
@@ -784,7 +832,9 @@ class Contract(ChildSlither, SourceMapping):
             list((Contract, Function|Variable)): List all of the external high level calls
         """
         all_high_level_calls = [f.all_high_level_calls() for f in self.functions + self.modifiers]  # type: ignore
-        all_high_level_calls = [item for sublist in all_high_level_calls for item in sublist]
+        all_high_level_calls = [
+            item for sublist in all_high_level_calls for item in sublist
+        ]
         return list(set(all_high_level_calls))
 
     # endregion
@@ -804,10 +854,14 @@ class Contract(ChildSlither, SourceMapping):
             (str, list, list, list, list): (name, inheritance, variables, fuction summaries, modifier summaries)
         """
         func_summaries = [
-            f.get_summary() for f in self.functions if (not f.is_shadowed or include_shadowed)
+            f.get_summary()
+            for f in self.functions
+            if (not f.is_shadowed or include_shadowed)
         ]
         modif_summaries = [
-            f.get_summary() for f in self.modifiers if (not f.is_shadowed or include_shadowed)
+            f.get_summary()
+            for f in self.modifiers
+            if (not f.is_shadowed or include_shadowed)
         ]
         return (
             self.name,
@@ -971,7 +1025,9 @@ class Contract(ChildSlither, SourceMapping):
     def is_from_dependency(self) -> bool:
         if self.slither.crytic_compile is None:
             return False
-        return self.slither.crytic_compile.is_dependency(self.source_mapping["filename_absolute"])
+        return self.slither.crytic_compile.is_dependency(
+            self.source_mapping["filename_absolute"]
+        )
 
     # endregion
     ###################################################################################
@@ -991,7 +1047,9 @@ class Contract(ChildSlither, SourceMapping):
                 if self.name == "Migrations":
                     paths = Path(self.source_mapping["filename_absolute"]).parts
                     if len(paths) >= 2:
-                        return paths[-2] == "contracts" and paths[-1] == "migrations.sol"
+                        return (
+                            paths[-2] == "contracts" and paths[-1] == "migrations.sol"
+                        )
         return False
 
     @property
@@ -1027,7 +1085,10 @@ class Contract(ChildSlither, SourceMapping):
             else:
                 for c in self.inheritance + [self]:
                     # This might lead to false positive
-                    if "upgradeable" in c.name.lower() or "upgradable" in c.name.lower():
+                    if (
+                        "upgradeable" in c.name.lower()
+                        or "upgradable" in c.name.lower()
+                    ):
                         self._is_upgradeable = True
                         break
         return self._is_upgradeable
@@ -1043,7 +1104,10 @@ class Contract(ChildSlither, SourceMapping):
                 if f.is_fallback:
                     for node in f.all_nodes():
                         for ir in node.irs:
-                            if isinstance(ir, LowLevelCall) and ir.function_name == "delegatecall":
+                            if (
+                                isinstance(ir, LowLevelCall)
+                                and ir.function_name == "delegatecall"
+                            ):
                                 self._is_upgradeable_proxy = True
                                 return self._is_upgradeable_proxy
                         if node.type == NodeType.ASSEMBLY:
@@ -1079,21 +1143,29 @@ class Contract(ChildSlither, SourceMapping):
                 if variable_candidate.expression and not variable_candidate.is_constant:
 
                     constructor_variable = Function()
-                    constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_VARIABLES)
+                    constructor_variable.set_function_type(
+                        FunctionType.CONSTRUCTOR_VARIABLES
+                    )
                     constructor_variable.set_contract(self)
                     constructor_variable.set_contract_declarer(self)
                     constructor_variable.set_visibility("internal")
                     # For now, source mapping of the constructor variable is the whole contract
                     # Could be improved with a targeted source mapping
                     constructor_variable.set_offset(self.source_mapping, self.slither)
-                    self._functions[constructor_variable.canonical_name] = constructor_variable
+                    self._functions[
+                        constructor_variable.canonical_name
+                    ] = constructor_variable
 
-                    prev_node = self._create_node(constructor_variable, 0, variable_candidate)
+                    prev_node = self._create_node(
+                        constructor_variable, 0, variable_candidate
+                    )
                     variable_candidate.node_initialization = prev_node
                     counter = 1
                     for v in self.state_variables[idx + 1 :]:
                         if v.expression and not v.is_constant:
-                            next_node = self._create_node(constructor_variable, counter, v)
+                            next_node = self._create_node(
+                                constructor_variable, counter, v
+                            )
                             v.node_initialization = next_node
                             prev_node.add_son(next_node)
                             next_node.add_father(prev_node)
@@ -1113,14 +1185,20 @@ class Contract(ChildSlither, SourceMapping):
                     # For now, source mapping of the constructor variable is the whole contract
                     # Could be improved with a targeted source mapping
                     constructor_variable.set_offset(self.source_mapping, self.slither)
-                    self._functions[constructor_variable.canonical_name] = constructor_variable
+                    self._functions[
+                        constructor_variable.canonical_name
+                    ] = constructor_variable
 
-                    prev_node = self._create_node(constructor_variable, 0, variable_candidate)
+                    prev_node = self._create_node(
+                        constructor_variable, 0, variable_candidate
+                    )
                     variable_candidate.node_initialization = prev_node
                     counter = 1
                     for v in self.state_variables[idx + 1 :]:
                         if v.expression and v.is_constant:
-                            next_node = self._create_node(constructor_variable, counter, v)
+                            next_node = self._create_node(
+                                constructor_variable, counter, v
+                            )
                             v.node_initialization = next_node
                             prev_node.add_son(next_node)
                             next_node.add_father(prev_node)
@@ -1142,7 +1220,10 @@ class Contract(ChildSlither, SourceMapping):
         node.set_function(func)
         func.add_node(node)
         expression = AssignmentOperation(
-            Identifier(variable), variable.expression, AssignmentOperationType.ASSIGN, variable.type
+            Identifier(variable),
+            variable.expression,
+            AssignmentOperationType.ASSIGN,
+            variable.type,
         )
 
         expression.set_offset(variable.source_mapping, self.slither)
@@ -1194,7 +1275,9 @@ class Contract(ChildSlither, SourceMapping):
                 last_state_variables_instances[variable_name] += instances
 
         for func in self.functions + self.modifiers:
-            func.fix_phi(last_state_variables_instances, initial_state_variables_instances)
+            func.fix_phi(
+                last_state_variables_instances, initial_state_variables_instances
+            )
 
     @property
     def is_top_level(self) -> bool:

+ 191 - 79
slither/core/declarations/function.py

@@ -14,7 +14,12 @@ from slither.core.declarations.solidity_variables import (
     SolidityVariable,
     SolidityVariableComposed,
 )
-from slither.core.expressions import Identifier, IndexAccess, MemberAccess, UnaryOperation
+from slither.core.expressions import (
+    Identifier,
+    IndexAccess,
+    MemberAccess,
+    UnaryOperation,
+)
 from slither.core.solidity_types import UserDefinedType
 from slither.core.solidity_types.type import Type
 from slither.core.source_mapping.source_mapping import SourceMapping
@@ -23,6 +28,8 @@ from slither.core.variables.local_variable import LocalVariable
 from slither.core.variables.state_variable import StateVariable
 from slither.utils.utils import unroll
 
+# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
+
 if TYPE_CHECKING:
     from slither.utils.type_helpers import (
         InternalCallType,
@@ -46,7 +53,10 @@ ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
 
 class ModifierStatements:
     def __init__(
-        self, modifier: Union["Contract", "Function"], entry_point: "Node", nodes: List["Node"]
+        self,
+        modifier: Union["Contract", "Function"],
+        entry_point: "Node",
+        nodes: List["Node"],
     ):
         self._modifier = modifier
         self._entry_point = entry_point
@@ -79,10 +89,26 @@ class FunctionType(Enum):
     FALLBACK = 2
     RECEIVE = 3
     CONSTRUCTOR_VARIABLES = 10  # Fake function to hold variable declaration statements
-    CONSTRUCTOR_CONSTANT_VARIABLES = 11  # Fake function to hold variable declaration statements
+    CONSTRUCTOR_CONSTANT_VARIABLES = (
+        11  # Fake function to hold variable declaration statements
+    )
 
 
-class Function(ChildContract, ChildInheritance, SourceMapping):
+def _filter_state_variables_written(expressions: List["Expression"]):
+    ret = []
+    for expression in expressions:
+        if isinstance(expression, Identifier):
+            ret.append(expression)
+        if isinstance(expression, UnaryOperation):
+            ret.append(expression.expression)
+        if isinstance(expression, MemberAccess):
+            ret.append(expression.expression)
+        if isinstance(expression, IndexAccess):
+            ret.append(expression.expression_left)
+    return ret
+
+
+class Function(ChildContract, ChildInheritance, SourceMapping):  # pylint: disable=too-many-public-methods
     """
         Function class
     """
@@ -147,13 +173,21 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         self._all_state_variables_written: Optional[List["StateVariable"]] = None
         self._all_slithir_variables: Optional[List["SlithIRVariable"]] = None
         self._all_nodes: Optional[List["Node"]] = None
-        self._all_conditional_state_variables_read: Optional[List["StateVariable"]] = None
-        self._all_conditional_state_variables_read_with_loop: Optional[List["StateVariable"]] = None
-        self._all_conditional_solidity_variables_read: Optional[List["SolidityVariable"]] = None
+        self._all_conditional_state_variables_read: Optional[
+            List["StateVariable"]
+        ] = None
+        self._all_conditional_state_variables_read_with_loop: Optional[
+            List["StateVariable"]
+        ] = None
+        self._all_conditional_solidity_variables_read: Optional[
+            List["SolidityVariable"]
+        ] = None
         self._all_conditional_solidity_variables_read_with_loop: Optional[
             List["SolidityVariable"]
         ] = None
-        self._all_solidity_variables_used_as_args: Optional[List["SolidityVariable"]] = None
+        self._all_solidity_variables_used_as_args: Optional[
+            List["SolidityVariable"]
+        ] = None
 
         self._is_shadowed: bool = False
         self._shadows: bool = False
@@ -187,13 +221,13 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         """
         if self._name == "" and self._function_type == FunctionType.CONSTRUCTOR:
             return "constructor"
-        elif self._function_type == FunctionType.FALLBACK:
+        if self._function_type == FunctionType.FALLBACK:
             return "fallback"
-        elif self._function_type == FunctionType.RECEIVE:
+        if self._function_type == FunctionType.RECEIVE:
             return "receive"
-        elif self._function_type == FunctionType.CONSTRUCTOR_VARIABLES:
+        if self._function_type == FunctionType.CONSTRUCTOR_VARIABLES:
             return "slitherConstructorVariables"
-        elif self._function_type == FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES:
+        if self._function_type == FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES:
             return "slitherConstructorConstantVariables"
         return self._name
 
@@ -815,15 +849,13 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         if self._return_values is None:
             return_values = list()
             returns = [n for n in self.nodes if n.type == NodeType.RETURN]
-            [
+            [  # pylint: disable=expression-not-assigned
                 return_values.extend(ir.values)
                 for node in returns
                 for ir in node.irs
                 if isinstance(ir, Return)
             ]
-            self._return_values = list(
-                set([x for x in return_values if not isinstance(x, Constant)])
-            )
+            self._return_values = list({x for x in return_values if not isinstance(x, Constant)})
         return self._return_values
 
     @property
@@ -838,15 +870,13 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         if self._return_values_ssa is None:
             return_values_ssa = list()
             returns = [n for n in self.nodes if n.type == NodeType.RETURN]
-            [
+            [  # pylint: disable=expression-not-assigned
                 return_values_ssa.extend(ir.values)
                 for node in returns
                 for ir in node.irs_ssa
                 if isinstance(ir, Return)
             ]
-            self._return_values_ssa = list(
-                set([x for x in return_values_ssa if not isinstance(x, Constant)])
-            )
+            self._return_values_ssa = list({x for x in return_values_ssa if not isinstance(x, Constant)})
         return self._return_values_ssa
 
     # endregion
@@ -900,7 +930,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         Contract and converted into address
         :return: the solidity signature
         """
-        parameters = [self._convert_type_for_solidity_signature(x.type) for x in self.parameters]
+        parameters = [
+            self._convert_type_for_solidity_signature(x.type) for x in self.parameters
+        ]
         return self.name + "(" + ",".join(parameters) + ")"
 
     @property
@@ -922,7 +954,14 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
             Return the function signature as a str (contains the return values)
         """
         name, parameters, returnVars = self.signature
-        return name + "(" + ",".join(parameters) + ") returns(" + ",".join(returnVars) + ")"
+        return (
+            name
+            + "("
+            + ",".join(parameters)
+            + ") returns("
+            + ",".join(returnVars)
+            + ")"
+        )
 
     # endregion
     ###################################################################################
@@ -977,10 +1016,14 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         values = f_new_values(self)
         explored = [self]
         to_explore = [
-            c for c in self.internal_calls if isinstance(c, Function) and c not in explored
+            c
+            for c in self.internal_calls
+            if isinstance(c, Function) and c not in explored
         ]
         to_explore += [
-            c for (_, c) in self.library_calls if isinstance(c, Function) and c not in explored
+            c
+            for (_, c) in self.library_calls
+            if isinstance(c, Function) and c not in explored
         ]
         to_explore += [m for m in self.modifiers if m not in explored]
 
@@ -1003,7 +1046,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
                 for (_, c) in f.library_calls
                 if isinstance(c, Function) and c not in explored and c not in to_explore
             ]
-            to_explore += [m for m in f.modifiers if m not in explored and m not in to_explore]
+            to_explore += [
+                m for m in f.modifiers if m not in explored and m not in to_explore
+            ]
 
         return list(set(values))
 
@@ -1029,7 +1074,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         """ recursive version of slithir_variables
         """
         if self._all_slithir_variables is None:
-            self._all_slithir_variables = self._explore_functions(lambda x: x.slithir_variables)
+            self._all_slithir_variables = self._explore_functions(
+                lambda x: x.slithir_variables
+            )
         return self._all_slithir_variables
 
     def all_nodes(self) -> List["Node"]:
@@ -1047,10 +1094,10 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         return self._all_expressions
 
     def all_slithir_operations(self) -> List["Operation"]:
-        """
-        """
         if self._all_slithir_operations is None:
-            self._all_slithir_operations = self._explore_functions(lambda x: x.slithir_operations)
+            self._all_slithir_operations = self._explore_functions(
+                lambda x: x.slithir_operations
+            )
         return self._all_slithir_operations
 
     def all_state_variables_written(self) -> List[StateVariable]:
@@ -1066,21 +1113,27 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         """ recursive version of internal_calls
         """
         if self._all_internals_calls is None:
-            self._all_internals_calls = self._explore_functions(lambda x: x.internal_calls)
+            self._all_internals_calls = self._explore_functions(
+                lambda x: x.internal_calls
+            )
         return self._all_internals_calls
 
     def all_low_level_calls(self) -> List["LowLevelCallType"]:
         """ recursive version of low_level calls
         """
         if self._all_low_level_calls is None:
-            self._all_low_level_calls = self._explore_functions(lambda x: x.low_level_calls)
+            self._all_low_level_calls = self._explore_functions(
+                lambda x: x.low_level_calls
+            )
         return self._all_low_level_calls
 
     def all_high_level_calls(self) -> List["HighLevelCallType"]:
         """ recursive version of high_level calls
         """
         if self._all_high_level_calls is None:
-            self._all_high_level_calls = self._explore_functions(lambda x: x.high_level_calls)
+            self._all_high_level_calls = self._explore_functions(
+                lambda x: x.high_level_calls
+            )
         return self._all_high_level_calls
 
     def all_library_calls(self) -> List["LibraryCallType"]:
@@ -1094,15 +1147,23 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         """ recursive version of solidity calls
         """
         if self._all_solidity_calls is None:
-            self._all_solidity_calls = self._explore_functions(lambda x: x.solidity_calls)
+            self._all_solidity_calls = self._explore_functions(
+                lambda x: x.solidity_calls
+            )
         return self._all_solidity_calls
 
     @staticmethod
-    def _explore_func_cond_read(func: "Function", include_loop: bool) -> List["StateVariable"]:
-        ret = [n.state_variables_read for n in func.nodes if n.is_conditional(include_loop)]
+    def _explore_func_cond_read(
+        func: "Function", include_loop: bool
+    ) -> List["StateVariable"]:
+        ret = [
+            n.state_variables_read for n in func.nodes if n.is_conditional(include_loop)
+        ]
         return [item for sublist in ret for item in sublist]
 
-    def all_conditional_state_variables_read(self, include_loop=True) -> List["StateVariable"]:
+    def all_conditional_state_variables_read(
+        self, include_loop=True
+    ) -> List["StateVariable"]:
         """
             Return the state variable used in a condition
 
@@ -1133,12 +1194,16 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
 
     @staticmethod
     def _explore_func_conditional(
-        func: "Function", f: Callable[["Node"], List[SolidityVariable]], include_loop: bool
+        func: "Function",
+        f: Callable[["Node"], List[SolidityVariable]],
+        include_loop: bool,
     ):
         ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)]
         return [item for sublist in ret for item in sublist]
 
-    def all_conditional_solidity_variables_read(self, include_loop=True) -> List[SolidityVariable]:
+    def all_conditional_solidity_variables_read(
+        self, include_loop=True
+    ) -> List[SolidityVariable]:
         """
             Return the Soldiity variables directly used in a condtion
 
@@ -1174,7 +1239,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         return [var for var in ret if isinstance(var, SolidityVariable)]
 
     @staticmethod
-    def _explore_func_nodes(func: "Function", f: Callable[["Node"], List[SolidityVariable]]):
+    def _explore_func_nodes(
+        func: "Function", f: Callable[["Node"], List[SolidityVariable]]
+    ):
         ret = [f(n) for n in func.nodes]
         return [item for sublist in ret for item in sublist]
 
@@ -1187,7 +1254,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         """
         if self._all_solidity_variables_used_as_args is None:
             self._all_solidity_variables_used_as_args = self._explore_functions(
-                lambda x: self._explore_func_nodes(x, self._solidity_variable_in_internal_calls)
+                lambda x: self._explore_func_nodes(
+                    x, self._solidity_variable_in_internal_calls
+                )
             )
         return self._all_solidity_variables_used_as_args
 
@@ -1217,7 +1286,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
     ###################################################################################
     ###################################################################################
 
-    def get_local_variable_from_name(self, variable_name: str) -> Optional[LocalVariable]:
+    def get_local_variable_from_name(
+        self, variable_name: str
+    ) -> Optional[LocalVariable]:
         """
             Return a local variable from a name
 
@@ -1271,7 +1342,11 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
             for node in self.nodes:
                 f.write('{}[label="{}"];\n'.format(node.node_id, description(node)))
                 if node.immediate_dominator:
-                    f.write("{}->{};\n".format(node.immediate_dominator.node_id, node.node_id))
+                    f.write(
+                        "{}->{};\n".format(
+                            node.immediate_dominator.node_id, node.node_id
+                        )
+                    )
 
             f.write("}\n")
 
@@ -1305,10 +1380,14 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
             if node.type in [NodeType.IF, NodeType.IFLOOP]:
                 true_node = node.son_true
                 if true_node:
-                    content += '{}->{}[label="True"];\n'.format(node.node_id, true_node.node_id)
+                    content += '{}->{}[label="True"];\n'.format(
+                        node.node_id, true_node.node_id
+                    )
                 false_node = node.son_false
                 if false_node:
-                    content += '{}->{}[label="False"];\n'.format(node.node_id, false_node.node_id)
+                    content += '{}->{}[label="False"];\n'.format(
+                        node.node_id, false_node.node_id
+                    )
             else:
                 for son in node.sons:
                     content += "{}->{};\n".format(node.node_id, son.node_id)
@@ -1353,7 +1432,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         Returns:
             bool: True if the variable is read
         """
-        variables_reads = [n.variables_read for n in self.nodes if n.contains_require_or_assert()]
+        variables_reads = [
+            n.variables_read for n in self.nodes if n.contains_require_or_assert()
+        ]
         variables_read = [item for sublist in variables_reads for item in sublist]
         return variable in variables_read
 
@@ -1401,7 +1482,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
 
         if self.is_constructor:
             return True
-        conditional_vars = self.all_conditional_solidity_variables_read(include_loop=False)
+        conditional_vars = self.all_conditional_solidity_variables_read(
+            include_loop=False
+        )
         args_vars = self.all_solidity_variables_used_as_args()
         return SolidityVariableComposed("msg.sender") in conditional_vars + args_vars
 
@@ -1412,19 +1495,6 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
     ###################################################################################
     ###################################################################################
 
-    def _filter_state_variables_written(self, expressions: List["Expression"]):
-        ret = []
-        for expression in expressions:
-            if isinstance(expression, Identifier):
-                ret.append(expression)
-            if isinstance(expression, UnaryOperation):
-                ret.append(expression.expression)
-            if isinstance(expression, MemberAccess):
-                ret.append(expression.expression)
-            if isinstance(expression, IndexAccess):
-                ret.append(expression.expression_left)
-        return ret
-
     def _analyze_read_write(self):
         """ Compute variables read/written/...
 
@@ -1436,7 +1506,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         # Remove dupplicate if they share the same string representation
         write_var = [
             next(obj)
-            for i, obj in groupby(sorted(write_var, key=lambda x: str(x)), lambda x: str(x))
+            for i, obj in groupby(
+                sorted(write_var, key=lambda x: str(x)), lambda x: str(x)
+            )
         ]
         self._expression_vars_written = write_var
 
@@ -1447,7 +1519,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         # Remove dupplicate if they share the same string representation
         write_var = [
             next(obj)
-            for i, obj in groupby(sorted(write_var, key=lambda x: str(x)), lambda x: str(x))
+            for i, obj in groupby(
+                sorted(write_var, key=lambda x: str(x)), lambda x: str(x)
+            )
         ]
         self._vars_written = write_var
 
@@ -1457,7 +1531,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         # Remove dupplicate if they share the same string representation
         read_var = [
             next(obj)
-            for i, obj in groupby(sorted(read_var, key=lambda x: str(x)), lambda x: str(x))
+            for i, obj in groupby(
+                sorted(read_var, key=lambda x: str(x)), lambda x: str(x)
+            )
         ]
         self._expression_vars_read = read_var
 
@@ -1467,14 +1543,18 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         # Remove dupplicate if they share the same string representation
         read_var = [
             next(obj)
-            for i, obj in groupby(sorted(read_var, key=lambda x: str(x)), lambda x: str(x))
+            for i, obj in groupby(
+                sorted(read_var, key=lambda x: str(x)), lambda x: str(x)
+            )
         ]
         self._vars_read = read_var
 
         self._state_vars_written = [
             x for x in self.variables_written if isinstance(x, StateVariable)
         ]
-        self._state_vars_read = [x for x in self.variables_read if isinstance(x, StateVariable)]
+        self._state_vars_read = [
+            x for x in self.variables_read if isinstance(x, StateVariable)
+        ]
         self._solidity_vars_read = [
             x for x in self.variables_read if isinstance(x, SolidityVariable)
         ]
@@ -1483,7 +1563,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
 
         slithir_variables = [x.slithir_variables for x in self.nodes]
         slithir_variables = [x for x in slithir_variables if x]
-        self._slithir_variables = [item for sublist in slithir_variables for item in sublist]
+        self._slithir_variables = [
+            item for sublist in slithir_variables for item in sublist
+        ]
 
     def _analyze_calls(self):
         calls = [x.calls_as_expression for x in self.nodes]
@@ -1496,7 +1578,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         internal_calls = [item for sublist in internal_calls for item in sublist]
         self._internal_calls = list(set(internal_calls))
 
-        self._solidity_calls = [c for c in internal_calls if isinstance(c, SolidityFunction)]
+        self._solidity_calls = [
+            c for c in internal_calls if isinstance(c, SolidityFunction)
+        ]
 
         low_level_calls = [x.low_level_calls for x in self.nodes]
         low_level_calls = [x for x in low_level_calls if x]
@@ -1513,7 +1597,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
         library_calls = [item for sublist in library_calls for item in sublist]
         self._library_calls = list(set(library_calls))
 
-        external_calls_as_expressions = [x.external_calls_as_expressions for x in self.nodes]
+        external_calls_as_expressions = [
+            x.external_calls_as_expressions for x in self.nodes
+        ]
         external_calls_as_expressions = [x for x in external_calls_as_expressions if x]
         external_calls_as_expressions = [
             item for sublist in external_calls_as_expressions for item in sublist
@@ -1548,6 +1634,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
     def _get_last_ssa_variable_instances(
         self, target_state: bool, target_local: bool
     ) -> Dict[str, Set["SlithIRVariable"]]:
+        # pylint: disable=too-many-locals,too-many-branches
         from slither.slithir.variables import ReferenceVariable
         from slither.slithir.operations import OperationWithLValue
         from slither.core.cfg.node import NodeType
@@ -1603,11 +1690,19 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
 
         return ret
 
-    def get_last_ssa_state_variables_instances(self) -> Dict[str, Set["SlithIRVariable"]]:
-        return self._get_last_ssa_variable_instances(target_state=True, target_local=False)
+    def get_last_ssa_state_variables_instances(
+        self,
+    ) -> Dict[str, Set["SlithIRVariable"]]:
+        return self._get_last_ssa_variable_instances(
+            target_state=True, target_local=False
+        )
 
-    def get_last_ssa_local_variables_instances(self) -> Dict[str, Set["SlithIRVariable"]]:
-        return self._get_last_ssa_variable_instances(target_state=False, target_local=True)
+    def get_last_ssa_local_variables_instances(
+        self,
+    ) -> Dict[str, Set["SlithIRVariable"]]:
+        return self._get_last_ssa_variable_instances(
+            target_state=False, target_local=True
+        )
 
     @staticmethod
     def _unchange_phi(ir: "Operation"):
@@ -1619,7 +1714,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
             return True
         return ir.rvalues[0] == ir.lvalue
 
-    def fix_phi(self, last_state_variables_instances, initial_state_variables_instances):
+    def fix_phi(
+        self, last_state_variables_instances, initial_state_variables_instances
+    ):
         from slither.slithir.operations import InternalCall, PhiCallback
         from slither.slithir.variables import Constant, StateIRVariable
 
@@ -1627,28 +1724,40 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
             for ir in node.irs_ssa:
                 if node == self.entry_point:
                     if isinstance(ir.lvalue, StateIRVariable):
-                        additional = [initial_state_variables_instances[ir.lvalue.canonical_name]]
-                        additional += last_state_variables_instances[ir.lvalue.canonical_name]
+                        additional = [
+                            initial_state_variables_instances[ir.lvalue.canonical_name]
+                        ]
+                        additional += last_state_variables_instances[
+                            ir.lvalue.canonical_name
+                        ]
                         ir.rvalues = list(set(additional + ir.rvalues))
                     # function parameter
                     else:
                         # find index of the parameter
                         idx = self.parameters.index(ir.lvalue.non_ssa_version)
                         # find non ssa version of that index
-                        additional = [n.ir.arguments[idx] for n in self.reachable_from_nodes]
+                        additional = [
+                            n.ir.arguments[idx] for n in self.reachable_from_nodes
+                        ]
                         additional = unroll(additional)
-                        additional = [a for a in additional if not isinstance(a, Constant)]
+                        additional = [
+                            a for a in additional if not isinstance(a, Constant)
+                        ]
                         ir.rvalues = list(set(additional + ir.rvalues))
                 if isinstance(ir, PhiCallback):
                     callee_ir = ir.callee_ir
                     if isinstance(callee_ir, InternalCall):
-                        last_ssa = callee_ir.function.get_last_ssa_state_variables_instances()
+                        last_ssa = (
+                            callee_ir.function.get_last_ssa_state_variables_instances()
+                        )
                         if ir.lvalue.canonical_name in last_ssa:
                             ir.rvalues = list(last_ssa[ir.lvalue.canonical_name])
                         else:
                             ir.rvalues = [ir.lvalue]
                     else:
-                        additional = last_state_variables_instances[ir.lvalue.canonical_name]
+                        additional = last_state_variables_instances[
+                            ir.lvalue.canonical_name
+                        ]
                         ir.rvalues = list(set(additional + ir.rvalues))
 
             node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)]
@@ -1662,7 +1771,10 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
 
     def generate_slithir_ssa(self, all_ssa_state_variables_instances):
         from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
-        from slither.core.dominators.utils import compute_dominance_frontier, compute_dominators
+        from slither.core.dominators.utils import (
+            compute_dominance_frontier,
+            compute_dominators,
+        )
 
         compute_dominators(self.nodes)
         compute_dominance_frontier(self.nodes)

+ 4 - 1
slither/core/declarations/pragma_directive.py

@@ -32,7 +32,10 @@ class Pragma(SourceMapping):
     @property
     def is_abi_encoder_v2(self) -> bool:
         if len(self._directive) == 2:
-            return self._directive[0] == "experimental" and self._directive[1] == "ABIEncoderV2"
+            return (
+                self._directive[0] == "experimental"
+                and self._directive[1] == "ABIEncoderV2"
+            )
         return False
 
     def __str__(self):

+ 9 - 4
slither/core/declarations/solidity_variables.py

@@ -3,6 +3,7 @@ from typing import List, Dict, Union
 
 from slither.core.context.context import Context
 from slither.core.solidity_types import ElementaryType, TypeInformation
+from slither.exceptions import SlitherException
 
 SOLIDITY_VARIABLES = {
     "now": "uint256",
@@ -90,8 +91,12 @@ class SolidityVariable(Context):
         self._name = name
 
     # dev function, will be removed once the code is stable
-    def _check_name(self, name: str):
-        assert name in SOLIDITY_VARIABLES or name.endswith("_slot") or name.endswith("_offset")
+    def _check_name(self, name: str):  # pylint: disable=no-self-use
+        assert (
+            name in SOLIDITY_VARIABLES
+            or name.endswith("_slot")
+            or name.endswith("_offset")
+        )
 
     @property
     def state_variable(self):
@@ -99,6 +104,8 @@ class SolidityVariable(Context):
             return self._name[:-5]
         if self._name.endswith("_offset"):
             return self._name[:-7]
+        to_log = f"Incorrect YUL parsing. {self} is not a solidity variable that can be seen as a state variable"
+        raise SlitherException(to_log)
 
     @property
     def name(self) -> str:
@@ -119,8 +126,6 @@ class SolidityVariable(Context):
 
 
 class SolidityVariableComposed(SolidityVariable):
-    def __init__(self, name: str):
-        super(SolidityVariableComposed, self).__init__(name)
 
     def _check_name(self, name: str):
         assert name in SOLIDITY_VARIABLES_COMPOSED

+ 1 - 1
slither/core/dominators/node_dominator_tree.py

@@ -7,7 +7,7 @@ if TYPE_CHECKING:
     from slither.core.cfg.node import Node
 
 
-class DominatorNode(object):
+class DominatorNode:
     def __init__(self):
         self._succ: Set["Node"] = set()
         self._nodes: List["Node"] = []

+ 1 - 0
slither/core/dominators/utils.py

@@ -43,6 +43,7 @@ def compute_dominators(nodes: List["Node"]):
 
         for dominator in node.dominators:
             if dominator != node:
+                # pylint: disable=expression-not-assigned
                 [
                     idom_candidates.remove(d)
                     for d in dominator.dominators

+ 10 - 2
slither/core/expressions/assignment_operation.py

@@ -50,7 +50,9 @@ class AssignmentOperationType(Enum):
         if operation_type == "%=":
             return AssignmentOperationType.ASSIGN_MODULO
 
-        raise SlitherCoreError("get_type: Unknown operation type {})".format(operation_type))
+        raise SlitherCoreError(
+            "get_type: Unknown operation type {})".format(operation_type)
+        )
 
     def __str__(self):
         if self == AssignmentOperationType.ASSIGN:
@@ -115,4 +117,10 @@ class AssignmentOperation(ExpressionTyped):
         return self._type
 
     def __str__(self):
-        return str(self.expression_left) + " " + str(self.type) + " " + str(self.expression_right)
+        return (
+            str(self.expression_left)
+            + " "
+            + str(self.type)
+            + " "
+            + str(self.expression_right)
+        )

+ 12 - 4
slither/core/expressions/binary_operation.py

@@ -41,7 +41,7 @@ class BinaryOperationType(Enum):
     RIGHT_SHIFT_ARITHMETIC = 23
 
     @staticmethod
-    def get_type(operation_type: "BinaryOperation"):
+    def get_type(operation_type: "BinaryOperation"):  # pylint: disable=too-many-branches
         if operation_type == "**":
             return BinaryOperationType.POWER
         if operation_type == "*":
@@ -91,9 +91,11 @@ class BinaryOperationType(Enum):
         if operation_type == ">>'":
             return BinaryOperationType.RIGHT_SHIFT_ARITHMETIC
 
-        raise SlitherCoreError("get_type: Unknown operation type {})".format(operation_type))
+        raise SlitherCoreError(
+            "get_type: Unknown operation type {})".format(operation_type)
+        )
 
-    def __str__(self):
+    def __str__(self):  # pylint: disable=too-many-branches
         if self == BinaryOperationType.POWER:
             return "**"
         if self == BinaryOperationType.MULTIPLICATION:
@@ -170,4 +172,10 @@ class BinaryOperation(ExpressionTyped):
         return self._type
 
     def __str__(self):
-        return str(self.expression_left) + " " + str(self.type) + " " + str(self.expression_right)
+        return (
+            str(self.expression_left)
+            + " "
+            + str(self.type)
+            + " "
+            + str(self.expression_right)
+        )

+ 1 - 1
slither/core/expressions/call_expression.py

@@ -3,7 +3,7 @@ from typing import Optional, List
 from slither.core.expressions.expression import Expression
 
 
-class CallExpression(Expression):
+class CallExpression(Expression):  # pylint: disable=too-many-instance-attributes
     def __init__(self, called, arguments, type_call):
         assert isinstance(called, Expression)
         super(CallExpression, self).__init__()

+ 4 - 0
slither/core/expressions/expression_typed.py

@@ -14,3 +14,7 @@ class ExpressionTyped(Expression):
     @property
     def type(self):
         return self._type
+
+    @type.setter
+    def type(self, new_type: "Type"):
+        self._type = new_type

+ 2 - 2
slither/core/expressions/literal.py

@@ -8,10 +8,10 @@ if TYPE_CHECKING:
 
 
 class Literal(Expression):
-    def __init__(self, value, type, subdenomination=None):
+    def __init__(self, value, custom_type, subdenomination=None):
         super(Literal, self).__init__()
         self._value: Union[int, str] = value
-        self._type = type
+        self._type = custom_type
         self._subdenomination: Optional[str] = subdenomination
 
     @property

+ 0 - 1
slither/core/expressions/super_call_expression.py

@@ -1,4 +1,3 @@
-from slither.core.expressions.expression import Expression
 from slither.core.expressions.call_expression import CallExpression
 
 

+ 8 - 5
slither/core/expressions/unary_operation.py

@@ -41,7 +41,9 @@ class UnaryOperationType(Enum):
                 return UnaryOperationType.PLUSPLUS_POST
             if operation_type == "--":
                 return UnaryOperationType.MINUSMINUS_POST
-        raise SlitherCoreError("get_type: Unknown operation type {}".format(operation_type))
+        raise SlitherCoreError(
+            "get_type: Unknown operation type {}".format(operation_type)
+        )
 
     def __str__(self):
         if self == UnaryOperationType.BANG:
@@ -76,13 +78,15 @@ class UnaryOperationType(Enum):
             UnaryOperationType.MINUS_PRE,
         ]:
             return True
-        elif operation_type in [
+        if operation_type in [
             UnaryOperationType.PLUSPLUS_POST,
             UnaryOperationType.MINUSMINUS_POST,
         ]:
             return False
 
-        raise SlitherCoreError("is_prefix: Unknown operation type {}".format(operation_type))
+        raise SlitherCoreError(
+            "is_prefix: Unknown operation type {}".format(operation_type)
+        )
 
 
 class UnaryOperation(ExpressionTyped):
@@ -117,5 +121,4 @@ class UnaryOperation(ExpressionTyped):
     def __str__(self):
         if self.is_prefix:
             return str(self.type) + " " + str(self._expression)
-        else:
-            return str(self._expression) + " " + str(self.type)
+        return str(self._expression) + " " + str(self.type)

+ 45 - 15
slither/core/slither_core.py

@@ -12,7 +12,15 @@ from typing import Optional, Dict, List, Set, Union, Tuple
 from crytic_compile import CryticCompile
 
 from slither.core.context.context import Context
-from slither.core.declarations import Contract, Pragma, Import, Function, Modifier, Structure, Enum
+from slither.core.declarations import (
+    Contract,
+    Pragma,
+    Import,
+    Function,
+    Modifier,
+    Structure,
+    Enum,
+)
 from slither.core.variables.state_variable import StateVariable
 from slither.slithir.operations import InternalCall
 from slither.slithir.variables import Constant
@@ -22,7 +30,14 @@ logger = logging.getLogger("Slither")
 logging.basicConfig()
 
 
-class SlitherCore(Context):
+def _relative_path_format(path: str) -> str:
+    """
+       Strip relative paths of "." and ".."
+    """
+    return path.split("..")[-1].strip(".").strip("/")
+
+
+class SlitherCore(Context):  # pylint: disable=too-many-instance-attributes,too-many-public-methods
     """
     Slither static analyzer
     """
@@ -115,6 +130,10 @@ class SlitherCore(Context):
             return self.crytic_compile.compiler_version.version
         return self._solc_version
 
+    @solc_version.setter
+    def solc_version(self, version: str):
+        self._solc_version = version
+
     @property
     def pragma_directives(self) -> List[Pragma]:
         """ list(core.declarations.Pragma): Pragma directives."""
@@ -142,14 +161,20 @@ class SlitherCore(Context):
         """list(Contract): List of contracts that are derived and not inherited."""
         inheritance = (x.inheritance for x in self.contracts)
         inheritance = [item for sublist in inheritance for item in sublist]
-        return [c for c in self._contracts.values() if c not in inheritance and not c.is_top_level]
+        return [
+            c
+            for c in self._contracts.values()
+            if c not in inheritance and not c.is_top_level
+        ]
 
     @property
     def contracts_as_dict(self) -> Dict[str, Contract]:
         """list(dict(str: Contract): List of contracts as dict: name -> Contract."""
         return self._contracts
 
-    def get_contract_from_name(self, contract_name: Union[str, Constant]) -> Optional[Contract]:
+    def get_contract_from_name(
+        self, contract_name: Union[str, Constant]
+    ) -> Optional[Contract]:
         """
             Return a contract from a name
         Args:
@@ -245,12 +270,6 @@ class SlitherCore(Context):
     ###################################################################################
     ###################################################################################
 
-    def relative_path_format(self, path: str) -> str:
-        """
-           Strip relative paths of "." and ".."
-        """
-        return path.split("..")[-1].strip(".").strip("/")
-
     def valid_result(self, r: Dict) -> bool:
         """
             Check if the result is valid
@@ -272,7 +291,7 @@ class SlitherCore(Context):
         for path in self._paths_to_filter:
             try:
                 if any(
-                    bool(re.search(self.relative_path_format(path), src_mapping))
+                    bool(re.search(_relative_path_format(path), src_mapping))
                     for src_mapping in source_mapping_elements
                 ):
                     matching = True
@@ -287,11 +306,15 @@ class SlitherCore(Context):
         if r["elements"] and matching:
             return False
         if r["elements"] and self._exclude_dependencies:
-            return not all(element["source_mapping"]["is_dependency"] for element in r["elements"])
+            return not all(
+                element["source_mapping"]["is_dependency"] for element in r["elements"]
+            )
         if r["id"] in self._previous_results_ids:
             return False
         # Conserve previous result filtering. This is conserved for compatibility, but is meant to be removed
-        return not r["description"] in [pr["description"] for pr in self._previous_results]
+        return not r["description"] in [
+            pr["description"] for pr in self._previous_results
+        ]
 
     def load_previous_results(self):
         filename = self._previous_results_filename
@@ -305,7 +328,11 @@ class SlitherCore(Context):
                                 self._previous_results_ids.add(r["id"])
         except json.decoder.JSONDecodeError:
             logger.error(
-                red("Impossible to decode {}. Consider removing the file".format(filename))
+                red(
+                    "Impossible to decode {}. Consider removing the file".format(
+                        filename
+                    )
+                )
             )
 
     def write_results_to_hide(self):
@@ -404,7 +431,10 @@ class SlitherCore(Context):
                     slot += 1
                     offset = 0
 
-                self._storage_layouts[contract.name][var.canonical_name] = (slot, offset)
+                self._storage_layouts[contract.name][var.canonical_name] = (
+                    slot,
+                    offset,
+                )
                 if new_slot:
                     slot += math.ceil(size / 32)
                 else:

+ 3 - 1
slither/core/solidity_types/elementary_type.py

@@ -123,7 +123,9 @@ MN = list(itertools.product(M, N))
 Fixed = ["fixed{}x{}".format(m, n) for (m, n) in MN] + ["fixed"]
 Ufixed = ["ufixed{}x{}".format(m, n) for (m, n) in MN] + ["ufixed"]
 
-ElementaryTypeName = ["address", "bool", "string", "var"] + Int + Uint + Byte + Fixed + Ufixed
+ElementaryTypeName = (
+    ["address", "bool", "string", "var"] + Int + Uint + Byte + Fixed + Ufixed
+)
 
 
 class NonElementaryType(Exception):

+ 3 - 1
slither/core/solidity_types/function_type.py

@@ -6,7 +6,9 @@ from slither.core.variables.function_type_variable import FunctionTypeVariable
 
 class FunctionType(Type):
     def __init__(
-        self, params: List[FunctionTypeVariable], return_values: List[FunctionTypeVariable]
+        self,
+        params: List[FunctionTypeVariable],
+        return_values: List[FunctionTypeVariable],
     ):
         assert all(isinstance(x, FunctionTypeVariable) for x in params)
         assert all(isinstance(x, FunctionTypeVariable) for x in return_values)

+ 1 - 0
slither/core/solidity_types/type_information.py

@@ -10,6 +10,7 @@ if TYPE_CHECKING:
 # https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
 class TypeInformation(Type):
     def __init__(self, c):
+        # pylint: disable=import-outside-toplevel
         from slither.core.declarations.contract import Contract
 
         assert isinstance(c, Contract)

+ 6 - 3
slither/core/solidity_types/user_defined_type.py

@@ -2,13 +2,14 @@ from typing import Union, TYPE_CHECKING, Tuple
 import math
 
 from slither.core.solidity_types.type import Type
+from slither.exceptions import SlitherException
 
 if TYPE_CHECKING:
     from slither.core.declarations.structure import Structure
     from slither.core.declarations.enum import Enum
     from slither.core.declarations.contract import Contract
 
-
+# pylint: disable=import-outside-toplevel
 class UserDefinedType(Type):
     def __init__(self, t):
         from slither.core.declarations.structure import Structure
@@ -31,9 +32,9 @@ class UserDefinedType(Type):
 
         if isinstance(self._type, Contract):
             return 20, False
-        elif isinstance(self._type, Enum):
+        if isinstance(self._type, Enum):
             return int(math.ceil(math.log2(len(self._type.values)) / 8)), False
-        elif isinstance(self._type, Structure):
+        if isinstance(self._type, Structure):
             # todo there's some duplicate logic here and slither_core, can we refactor this?
             slot = 0
             offset = 0
@@ -54,6 +55,8 @@ class UserDefinedType(Type):
             if offset > 0:
                 slot += 1
             return slot * 32, True
+        to_log = f"{self} does not have storage size"
+        raise SlitherException(to_log)
 
     def __str__(self):
         from slither.core.declarations.structure import Structure

+ 8 - 4
slither/core/source_mapping/source_mapping.py

@@ -58,7 +58,7 @@ class SourceMapping(Context):
         return lines, starting_column, ending_column
 
     @staticmethod
-    def _convert_source_mapping(offset: str, slither):
+    def _convert_source_mapping(offset: str, slither):  # pylint: disable=too-many-locals
         """
         Convert a text offset to a real offset
         see https://solidity.readthedocs.io/en/develop/miscellaneous.html#source-mappings
@@ -112,10 +112,14 @@ class SourceMapping(Context):
 
         if slither.crytic_compile and filename in slither.crytic_compile.src_content:
             source_code = slither.crytic_compile.src_content[filename]
-            (lines, starting_column, ending_column) = SourceMapping._compute_line(source_code, s, l)
+            (lines, starting_column, ending_column) = SourceMapping._compute_line(
+                source_code, s, l
+            )
         elif filename in slither.source_code:
             source_code = slither.source_code[filename]
-            (lines, starting_column, ending_column) = SourceMapping._compute_line(source_code, s, l)
+            (lines, starting_column, ending_column) = SourceMapping._compute_line(
+                source_code, s, l
+            )
         else:
             (lines, starting_column, ending_column) = ([], None, None)
 
@@ -145,7 +149,7 @@ class SourceMapping(Context):
         elif len(lines) == 1:
             lines = "#{}{}".format(line_descr, lines[0])
         else:
-            lines = "#{}{}-{}{}".format(line_descr, lines[0], line_descr, lines[-1])
+            lines = f"#{line_descr}{lines[0]}-{line_descr}{lines[-1]}"
         return lines
 
     def source_mapping_to_markdown(self, markdown_root: str) -> str:

+ 1 - 1
slither/core/variables/event_variable.py

@@ -1,4 +1,4 @@
-from .variable import Variable
+from slither.core.variables.variable import Variable
 from slither.core.children.child_event import ChildEvent
 
 

+ 1 - 1
slither/core/variables/local_variable.py

@@ -1,6 +1,6 @@
 from typing import Optional
 
-from .variable import Variable
+from slither.core.variables.variable import Variable
 from slither.core.children.child_function import ChildFunction
 from slither.core.solidity_types.user_defined_type import UserDefinedType
 from slither.core.solidity_types.array_type import ArrayType

+ 14 - 3
slither/core/variables/state_variable.py

@@ -1,6 +1,6 @@
 from typing import Optional, TYPE_CHECKING, Tuple, List
 
-from .variable import Variable
+from slither.core.variables.variable import Variable
 from slither.core.children.child_contract import ChildContract
 from slither.utils.type import export_nested_types_from_variable
 
@@ -34,7 +34,11 @@ class StateVariable(ChildContract, Variable):
             Return the signature of the state variable as a function signature
             :return: (str, list(str), list(str)), as (name, list parameters type, list return values type)
         """
-        return self.name, [str(x) for x in export_nested_types_from_variable(self)], str(self.type)
+        return (
+            self.name,
+            [str(x) for x in export_nested_types_from_variable(self)],
+            str(self.type),
+        )
 
     @property
     def signature_str(self) -> str:
@@ -43,7 +47,14 @@ class StateVariable(ChildContract, Variable):
             :return: str: func_name(type1,type2) returns(type3)
         """
         name, parameters, returnVars = self.signature
-        return name + "(" + ",".join(parameters) + ") returns(" + ",".join(returnVars) + ")"
+        return (
+            name
+            + "("
+            + ",".join(parameters)
+            + ") returns("