We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
slither-flat: Translate all visibilities to internal
Similar to the `external` to `public` conversion, we can convert all visible functions to `internal`, and all `private` variables to `internal`.

This schema is useful when fuzzing a codebase with Echidna, to reduce the scope of the fuzzing and allow to access private elements.
slither-flat: Translate all visibilities to internal
Similar to the `external` to `public` conversion, we can convert all visible functions to `internal`, and all `private` variables to `internal`.

This schema is useful when fuzzing a codebase with Echidna, to reduce the scope of the fuzzing and allow to access private elements.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `slither/tools/flattening/__main__.py`
Content:
```
1 import argparse
2 import logging
3 from slither import Slither
4 from crytic_compile import cryticparser
5 from .flattening import Flattening
6 
7 logging.basicConfig()
8 logging.getLogger("Slither").setLevel(logging.INFO)
9 logger = logging.getLogger("Slither-flattening")
10 logger.setLevel(logging.INFO)
11 
12 def parse_args():
13     """
14     Parse the underlying arguments for the program.
15     :return: Returns the arguments for the program.
16     """
17     parser = argparse.ArgumentParser(description='Contracts flattening',
18                                      usage='slither-flat filename')
19 
20     parser.add_argument('filename',
21                         help='The filename of the contract or project to analyze.')
22 
23     parser.add_argument('--convert-external',
24                         help='Convert external to public.',
25                         action='store_true')
26 
27     parser.add_argument('--remove-assert',
28                         help='Remove call to assert().',
29                         action='store_true')
30 
31     parser.add_argument('--contract',
32                         help='Flatten a specific contract (default: all most derived contracts).',
33                         default=None)
34 
35     # Add default arguments from crytic-compile
36     cryticparser.init(parser)
37 
38     return parser.parse_args()
39 
40 
41 def main():
42     args = parse_args()
43 
44     slither = Slither(args.filename, **vars(args))
45     flat = Flattening(slither, external_to_public=args.convert_external, remove_assert=args.remove_assert)
46 
47     flat.export(target=args.contract)
48 
49 
50 if __name__ == '__main__':
51     main()
52
```

Path: `slither/tools/flattening/flattening.py`
Content:
```
1 from pathlib import Path
2 import re
3 import logging
4 from collections import namedtuple
5 
6 from slither.core.declarations import SolidityFunction
7 from slither.exceptions import SlitherException
8 from slither.core.solidity_types.user_defined_type import UserDefinedType
9 from slither.core.declarations.structure import Structure
10 from slither.core.declarations.enum import Enum
11 from slither.core.declarations.contract import Contract
12 from slither.slithir.operations import NewContract, TypeConversion, SolidityCall
13 
14 logger = logging.getLogger("Slither-flattening")
15 
16 # index: where to start
17 # patch_type:
18 #   - public_to_external: public to external (external-to-public)
19 #   - calldata_to_memory: calldata to memory (external-to-public)
20 #   - line_removal: remove the line (remove-assert)
21 Patch = namedtuple('PatchExternal', ['index', 'patch_type'])
22 
23 class Flattening:
24     DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')
25 
26     def __init__(self, slither, external_to_public=False, remove_assert=False):
27         self._source_codes = {}
28         self._slither = slither
29         self._external_to_public = external_to_public
30         self._remove_assert = remove_assert
31         self._use_abi_encoder_v2 = False
32 
33         self._check_abi_encoder_v2()
34 
35         for contract in slither.contracts:
36             self._get_source_code(contract)
37 
38     def _check_abi_encoder_v2(self):
39         for p in self._slither.pragma_directives:
40             if 'ABIEncoderV2' in str(p.directive):
41                 self._use_abi_encoder_v2 = True
42                 return
43 
44     def _get_source_code(self, contract):
45         src_mapping = contract.source_mapping
46         content = self._slither.source_code[src_mapping['filename_absolute']]
47         start = src_mapping['start']
48         end = src_mapping['start'] + src_mapping['length']
49         first_line = src_mapping['lines'][0]
50 
51         to_patch = []
52         # interface must use external
53         if self._external_to_public and contract.contract_kind != "interface":
54             for f in contract.functions_declared:
55                 # fallback must be external
56                 if f.is_fallback or f.is_constructor_variables:
57                     continue
58                 if f.visibility == 'external':
59                     attributes_start = (f.parameters_src.source_mapping['start'] +
60                                         f.parameters_src.source_mapping['length'])
61                     attributes_end = f.returns_src.source_mapping['start']
62                     attributes = content[attributes_start:attributes_end]
63                     regex = re.search(r'((\sexternal)\s+)|(\sexternal)$|(\)external)$', attributes)
64                     if regex:
65                         to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'public_to_external'))
66                     else:
67                         raise SlitherException(f'External keyword not found {f.name} {attributes}')
68 
69                     for var in f.parameters:
70                         if var.location == "calldata":
71                             calldata_start = var.source_mapping['start']
72                             calldata_end = calldata_start + var.source_mapping['length']
73                             calldata_idx = content[calldata_start:calldata_end].find(' calldata ')
74                             to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))
75 
76         if self._remove_assert:
77             for function in contract.functions_and_modifiers_declared:
78                 for node in function.nodes:
79                     for ir in node.irs:
80                         if isinstance(ir, SolidityCall) and ir.function == SolidityFunction('assert(bool)'):
81                             to_patch.append(Patch(node.source_mapping['start'], 'line_removal'))
82                             logger.info(f'Code commented: {node.expression} ({node.source_mapping_str})')
83 
84         to_patch.sort(key=lambda x: x.index, reverse=True)
85 
86         content = content[start:end]
87         for patch in to_patch:
88             patch_type = patch.patch_type
89             index = patch.index
90             index = index - start
91             if patch_type == 'public_to_external':
92                 content = content[:index] + 'public' + content[index + len('external'):]
93             elif patch_type == 'calldata_to_memory':
94                 content = content[:index] + 'memory' + content[index + len('calldata'):]
95             else:
96                 assert patch_type == 'line_removal'
97                 content = content[:index] + ' // ' + content[index:]
98 
99         self._source_codes[contract] = content
100 
101     def _export_from_type(self, t, contract, exported, list_contract):
102         if isinstance(t, UserDefinedType):
103             if isinstance(t.type, (Enum, Structure)):
104                 if t.type.contract != contract and not t.type.contract in exported:
105                     self._export_contract(t.type.contract, exported, list_contract)
106             else:
107                 assert isinstance(t.type, Contract)
108                 if t.type != contract and not t.type in exported:
109                     self._export_contract(t.type, exported, list_contract)
110 
111     def _export_contract(self, contract, exported, list_contract):
112         if contract.name in exported:
113             return
114         exported.add(contract.name)
115         for inherited in contract.inheritance:
116             self._export_contract(inherited, exported, list_contract)
117 
118         # Find all the external contracts called
119         externals = contract.all_library_calls + contract.all_high_level_calls
120         # externals is a list of (contract, function)
121         # We also filter call to itself to avoid infilite loop
122         externals = list(set([e[0] for e in externals if e[0] != contract]))
123 
124         for inherited in externals:
125             self._export_contract(inherited, exported, list_contract)
126 
127         # Find all the external contracts use as a base type
128         local_vars = []
129         for f in contract.functions_declared:
130             local_vars += f.variables
131 
132         for v in contract.variables + local_vars:
133             self._export_from_type(v.type, contract, exported, list_contract)
134 
135         # Find all convert and "new" operation that can lead to use an external contract
136         for f in contract.functions_declared:
137             for ir in f.slithir_operations:
138                 if isinstance(ir, NewContract):
139                     if ir.contract_created != contract and not ir.contract_created in exported:
140                         self._export_contract(ir.contract_created, exported, list_contract)
141                 if isinstance(ir, TypeConversion):
142                     self._export_from_type(ir.type, contract, exported, list_contract)
143         list_contract.append(self._source_codes[contract])
144 
145     def _export(self, contract, ret):
146         self._export_contract(contract, set(), ret)
147         path = Path(self.DEFAULT_EXPORT_PATH, f'{contract.name}.sol')
148         logger.info(f'Export {path}')
149         with open(path, 'w') as f:
150             if self._slither.solc_version:
151                 f.write(f'pragma solidity {self._slither.solc_version};\n')
152             if self._use_abi_encoder_v2:
153                 f.write('pragma experimental ABIEncoderV2;\n')
154             f.write('\n'.join(ret))
155             f.write('\n')
156 
157     def export(self, target=None):
158 
159         if not self.DEFAULT_EXPORT_PATH.exists():
160             self.DEFAULT_EXPORT_PATH.mkdir(parents=True)
161 
162         if target is None:
163             for contract in self._slither.contracts_derived:
164                 ret = []
165                 self._export(contract, ret)
166         else:
167             contract = self._slither.get_contract_from_name(target)
168             if contract is None:
169                 logger.error(f'{target} not found')
170             else:
171                 ret = []
172                 self._export(contract, ret)
173
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/slither/tools/flattening/__main__.py b/slither/tools/flattening/__main__.py
--- a/slither/tools/flattening/__main__.py
+++ b/slither/tools/flattening/__main__.py
@@ -24,6 +24,10 @@
                         help='Convert external to public.',
                         action='store_true')
 
+    parser.add_argument('--convert-private',
+                        help='Convert private variables to internal.',
+                        action='store_true')
+
     parser.add_argument('--remove-assert',
                         help='Remove call to assert().',
                         action='store_true')
@@ -42,7 +46,10 @@
     args = parse_args()
 
     slither = Slither(args.filename, **vars(args))
-    flat = Flattening(slither, external_to_public=args.convert_external, remove_assert=args.remove_assert)
+    flat = Flattening(slither,
+                      external_to_public=args.convert_external,
+                      remove_assert=args.remove_assert,
+                      private_to_internal=args.convert_private)
 
     flat.export(target=args.contract)
 
diff --git a/slither/tools/flattening/flattening.py b/slither/tools/flattening/flattening.py
--- a/slither/tools/flattening/flattening.py
+++ b/slither/tools/flattening/flattening.py
@@ -23,12 +23,13 @@
 class Flattening:
     DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')
 
-    def __init__(self, slither, external_to_public=False, remove_assert=False):
+    def __init__(self, slither, external_to_public=False, remove_assert=False, private_to_internal=False):
         self._source_codes = {}
         self._slither = slither
         self._external_to_public = external_to_public
         self._remove_assert = remove_assert
         self._use_abi_encoder_v2 = False
+        self._private_to_internal = private_to_internal
 
         self._check_abi_encoder_v2()
 
@@ -46,7 +47,6 @@
         content = self._slither.source_code[src_mapping['filename_absolute']]
         start = src_mapping['start']
         end = src_mapping['start'] + src_mapping['length']
-        first_line = src_mapping['lines'][0]
 
         to_patch = []
         # interface must use external
@@ -73,6 +73,20 @@
                             calldata_idx = content[calldata_start:calldata_end].find(' calldata ')
                             to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))
 
+        if self._private_to_internal:
+            for variable in contract.state_variables_declared:
+                if variable.visibility == 'private':
+                    print(variable.source_mapping)
+                    attributes_start = variable.source_mapping['start']
+                    attributes_end = attributes_start + variable.source_mapping['length']
+                    attributes = content[attributes_start:attributes_end]
+                    print(attributes)
+                    regex = re.search(r' private ', attributes)
+                    if regex:
+                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'private_to_internal'))
+                    else:
+                        raise SlitherException(f'private keyword not found {v.name} {attributes}')
+
         if self._remove_assert:
             for function in contract.functions_and_modifiers_declared:
                 for node in function.nodes:
@@ -90,6 +104,8 @@
             index = index - start
             if patch_type == 'public_to_external':
                 content = content[:index] + 'public' + content[index + len('external'):]
+            if patch_type == 'private_to_internal':
+                content = content[:index] + 'internal' + content[index + len('private'):]
             elif patch_type == 'calldata_to_memory':
                 content = content[:index] + 'memory' + content[index + len('calldata'):]
             else:

{"golden_diff": "diff --git a/slither/tools/flattening/__main__.py b/slither/tools/flattening/__main__.py\n--- a/slither/tools/flattening/__main__.py\n+++ b/slither/tools/flattening/__main__.py\n@@ -24,6 +24,10 @@\n                         help='Convert external to public.',\n                         action='store_true')\n \n+    parser.add_argument('--convert-private',\n+                        help='Convert private variables to internal.',\n+                        action='store_true')\n+\n     parser.add_argument('--remove-assert',\n                         help='Remove call to assert().',\n                         action='store_true')\n@@ -42,7 +46,10 @@\n     args = parse_args()\n \n     slither = Slither(args.filename, **vars(args))\n-    flat = Flattening(slither, external_to_public=args.convert_external, remove_assert=args.remove_assert)\n+    flat = Flattening(slither,\n+                      external_to_public=args.convert_external,\n+                      remove_assert=args.remove_assert,\n+                      private_to_internal=args.convert_private)\n \n     flat.export(target=args.contract)\n \ndiff --git a/slither/tools/flattening/flattening.py b/slither/tools/flattening/flattening.py\n--- a/slither/tools/flattening/flattening.py\n+++ b/slither/tools/flattening/flattening.py\n@@ -23,12 +23,13 @@\n class Flattening:\n     DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')\n \n-    def __init__(self, slither, external_to_public=False, remove_assert=False):\n+    def __init__(self, slither, external_to_public=False, remove_assert=False, private_to_internal=False):\n         self._source_codes = {}\n         self._slither = slither\n         self._external_to_public = external_to_public\n         self._remove_assert = remove_assert\n         self._use_abi_encoder_v2 = False\n+        self._private_to_internal = private_to_internal\n \n         self._check_abi_encoder_v2()\n \n@@ -46,7 +47,6 @@\n         content = self._slither.source_code[src_mapping['filename_absolute']]\n         start = src_mapping['start']\n         end = src_mapping['start'] + src_mapping['length']\n-        first_line = src_mapping['lines'][0]\n \n         to_patch = []\n         # interface must use external\n@@ -73,6 +73,20 @@\n                             calldata_idx = content[calldata_start:calldata_end].find(' calldata ')\n                             to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))\n \n+        if self._private_to_internal:\n+            for variable in contract.state_variables_declared:\n+                if variable.visibility == 'private':\n+                    print(variable.source_mapping)\n+                    attributes_start = variable.source_mapping['start']\n+                    attributes_end = attributes_start + variable.source_mapping['length']\n+                    attributes = content[attributes_start:attributes_end]\n+                    print(attributes)\n+                    regex = re.search(r' private ', attributes)\n+                    if regex:\n+                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'private_to_internal'))\n+                    else:\n+                        raise SlitherException(f'private keyword not found {v.name} {attributes}')\n+\n         if self._remove_assert:\n             for function in contract.functions_and_modifiers_declared:\n                 for node in function.nodes:\n@@ -90,6 +104,8 @@\n             index = index - start\n             if patch_type == 'public_to_external':\n                 content = content[:index] + 'public' + content[index + len('external'):]\n+            if patch_type == 'private_to_internal':\n+                content = content[:index] + 'internal' + content[index + len('private'):]\n             elif patch_type == 'calldata_to_memory':\n                 content = content[:index] + 'memory' + content[index + len('calldata'):]\n             else:\n", "issue": "slither-flat: Translate all visibilities to internal\nSimilar to the `external` to `public` conversion, we can convert all visible functions to `internal`, and all `private` variables to `internal`.\r\n\r\nThis schema is useful when fuzzing a codebase with Echidna, to reduce the scope of the fuzzing and allow to access private elements.\nslither-flat: Translate all visibilities to internal\nSimilar to the `external` to `public` conversion, we can convert all visible functions to `internal`, and all `private` variables to `internal`.\r\n\r\nThis schema is useful when fuzzing a codebase with Echidna, to reduce the scope of the fuzzing and allow to access private elements.\n", "before_files": [{"content": "import argparse\nimport logging\nfrom slither import Slither\nfrom crytic_compile import cryticparser\nfrom .flattening import Flattening\n\nlogging.basicConfig()\nlogging.getLogger(\"Slither\").setLevel(logging.INFO)\nlogger = logging.getLogger(\"Slither-flattening\")\nlogger.setLevel(logging.INFO)\n\ndef parse_args():\n    \"\"\"\n    Parse the underlying arguments for the program.\n    :return: Returns the arguments for the program.\n    \"\"\"\n    parser = argparse.ArgumentParser(description='Contracts flattening',\n                                     usage='slither-flat filename')\n\n    parser.add_argument('filename',\n                        help='The filename of the contract or project to analyze.')\n\n    parser.add_argument('--convert-external',\n                        help='Convert external to public.',\n                        action='store_true')\n\n    parser.add_argument('--remove-assert',\n                        help='Remove call to assert().',\n                        action='store_true')\n\n    parser.add_argument('--contract',\n                        help='Flatten a specific contract (default: all most derived contracts).',\n                        default=None)\n\n    # Add default arguments from crytic-compile\n    cryticparser.init(parser)\n\n    return parser.parse_args()\n\n\ndef main():\n    args = parse_args()\n\n    slither = Slither(args.filename, **vars(args))\n    flat = Flattening(slither, external_to_public=args.convert_external, remove_assert=args.remove_assert)\n\n    flat.export(target=args.contract)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "slither/tools/flattening/__main__.py"}, {"content": "from pathlib import Path\nimport re\nimport logging\nfrom collections import namedtuple\n\nfrom slither.core.declarations import SolidityFunction\nfrom slither.exceptions import SlitherException\nfrom slither.core.solidity_types.user_defined_type import UserDefinedType\nfrom slither.core.declarations.structure import Structure\nfrom slither.core.declarations.enum import Enum\nfrom slither.core.declarations.contract import Contract\nfrom slither.slithir.operations import NewContract, TypeConversion, SolidityCall\n\nlogger = logging.getLogger(\"Slither-flattening\")\n\n# index: where to start\n# patch_type:\n#   - public_to_external: public to external (external-to-public)\n#   - calldata_to_memory: calldata to memory (external-to-public)\n#   - line_removal: remove the line (remove-assert)\nPatch = namedtuple('PatchExternal', ['index', 'patch_type'])\n\nclass Flattening:\n    DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')\n\n    def __init__(self, slither, external_to_public=False, remove_assert=False):\n        self._source_codes = {}\n        self._slither = slither\n        self._external_to_public = external_to_public\n        self._remove_assert = remove_assert\n        self._use_abi_encoder_v2 = False\n\n        self._check_abi_encoder_v2()\n\n        for contract in slither.contracts:\n            self._get_source_code(contract)\n\n    def _check_abi_encoder_v2(self):\n        for p in self._slither.pragma_directives:\n            if 'ABIEncoderV2' in str(p.directive):\n                self._use_abi_encoder_v2 = True\n                return\n\n    def _get_source_code(self, contract):\n        src_mapping = contract.source_mapping\n        content = self._slither.source_code[src_mapping['filename_absolute']]\n        start = src_mapping['start']\n        end = src_mapping['start'] + src_mapping['length']\n        first_line = src_mapping['lines'][0]\n\n        to_patch = []\n        # interface must use external\n        if self._external_to_public and contract.contract_kind != \"interface\":\n            for f in contract.functions_declared:\n                # fallback must be external\n                if f.is_fallback or f.is_constructor_variables:\n                    continue\n                if f.visibility == 'external':\n                    attributes_start = (f.parameters_src.source_mapping['start'] +\n                                        f.parameters_src.source_mapping['length'])\n                    attributes_end = f.returns_src.source_mapping['start']\n                    attributes = content[attributes_start:attributes_end]\n                    regex = re.search(r'((\\sexternal)\\s+)|(\\sexternal)$|(\\)external)$', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'public_to_external'))\n                    else:\n                        raise SlitherException(f'External keyword not found {f.name} {attributes}')\n\n                    for var in f.parameters:\n                        if var.location == \"calldata\":\n                            calldata_start = var.source_mapping['start']\n                            calldata_end = calldata_start + var.source_mapping['length']\n                            calldata_idx = content[calldata_start:calldata_end].find(' calldata ')\n                            to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))\n\n        if self._remove_assert:\n            for function in contract.functions_and_modifiers_declared:\n                for node in function.nodes:\n                    for ir in node.irs:\n                        if isinstance(ir, SolidityCall) and ir.function == SolidityFunction('assert(bool)'):\n                            to_patch.append(Patch(node.source_mapping['start'], 'line_removal'))\n                            logger.info(f'Code commented: {node.expression} ({node.source_mapping_str})')\n\n        to_patch.sort(key=lambda x: x.index, reverse=True)\n\n        content = content[start:end]\n        for patch in to_patch:\n            patch_type = patch.patch_type\n            index = patch.index\n            index = index - start\n            if patch_type == 'public_to_external':\n                content = content[:index] + 'public' + content[index + len('external'):]\n            elif patch_type == 'calldata_to_memory':\n                content = content[:index] + 'memory' + content[index + len('calldata'):]\n            else:\n                assert patch_type == 'line_removal'\n                content = content[:index] + ' // ' + content[index:]\n\n        self._source_codes[contract] = content\n\n    def _export_from_type(self, t, contract, exported, list_contract):\n        if isinstance(t, UserDefinedType):\n            if isinstance(t.type, (Enum, Structure)):\n                if t.type.contract != contract and not t.type.contract in exported:\n                    self._export_contract(t.type.contract, exported, list_contract)\n            else:\n                assert isinstance(t.type, Contract)\n                if t.type != contract and not t.type in exported:\n                    self._export_contract(t.type, exported, list_contract)\n\n    def _export_contract(self, contract, exported, list_contract):\n        if contract.name in exported:\n            return\n        exported.add(contract.name)\n        for inherited in contract.inheritance:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts called\n        externals = contract.all_library_calls + contract.all_high_level_calls\n        # externals is a list of (contract, function)\n        # We also filter call to itself to avoid infilite loop\n        externals = list(set([e[0] for e in externals if e[0] != contract]))\n\n        for inherited in externals:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts use as a base type\n        local_vars = []\n        for f in contract.functions_declared:\n            local_vars += f.variables\n\n        for v in contract.variables + local_vars:\n            self._export_from_type(v.type, contract, exported, list_contract)\n\n        # Find all convert and \"new\" operation that can lead to use an external contract\n        for f in contract.functions_declared:\n            for ir in f.slithir_operations:\n                if isinstance(ir, NewContract):\n                    if ir.contract_created != contract and not ir.contract_created in exported:\n                        self._export_contract(ir.contract_created, exported, list_contract)\n                if isinstance(ir, TypeConversion):\n                    self._export_from_type(ir.type, contract, exported, list_contract)\n        list_contract.append(self._source_codes[contract])\n\n    def _export(self, contract, ret):\n        self._export_contract(contract, set(), ret)\n        path = Path(self.DEFAULT_EXPORT_PATH, f'{contract.name}.sol')\n        logger.info(f'Export {path}')\n        with open(path, 'w') as f:\n            if self._slither.solc_version:\n                f.write(f'pragma solidity {self._slither.solc_version};\\n')\n            if self._use_abi_encoder_v2:\n                f.write('pragma experimental ABIEncoderV2;\\n')\n            f.write('\\n'.join(ret))\n            f.write('\\n')\n\n    def export(self, target=None):\n\n        if not self.DEFAULT_EXPORT_PATH.exists():\n            self.DEFAULT_EXPORT_PATH.mkdir(parents=True)\n\n        if target is None:\n            for contract in self._slither.contracts_derived:\n                ret = []\n                self._export(contract, ret)\n        else:\n            contract = self._slither.get_contract_from_name(target)\n            if contract is None:\n                logger.error(f'{target} not found')\n            else:\n                ret = []\n                self._export(contract, ret)\n", "path": "slither/tools/flattening/flattening.py"}], "after_files": [{"content": "import argparse\nimport logging\nfrom slither import Slither\nfrom crytic_compile import cryticparser\nfrom .flattening import Flattening\n\nlogging.basicConfig()\nlogging.getLogger(\"Slither\").setLevel(logging.INFO)\nlogger = logging.getLogger(\"Slither-flattening\")\nlogger.setLevel(logging.INFO)\n\ndef parse_args():\n    \"\"\"\n    Parse the underlying arguments for the program.\n    :return: Returns the arguments for the program.\n    \"\"\"\n    parser = argparse.ArgumentParser(description='Contracts flattening',\n                                     usage='slither-flat filename')\n\n    parser.add_argument('filename',\n                        help='The filename of the contract or project to analyze.')\n\n    parser.add_argument('--convert-external',\n                        help='Convert external to public.',\n                        action='store_true')\n\n    parser.add_argument('--convert-private',\n                        help='Convert private variables to internal.',\n                        action='store_true')\n\n    parser.add_argument('--remove-assert',\n                        help='Remove call to assert().',\n                        action='store_true')\n\n    parser.add_argument('--contract',\n                        help='Flatten a specific contract (default: all most derived contracts).',\n                        default=None)\n\n    # Add default arguments from crytic-compile\n    cryticparser.init(parser)\n\n    return parser.parse_args()\n\n\ndef main():\n    args = parse_args()\n\n    slither = Slither(args.filename, **vars(args))\n    flat = Flattening(slither,\n                      external_to_public=args.convert_external,\n                      remove_assert=args.remove_assert,\n                      private_to_internal=args.convert_private)\n\n    flat.export(target=args.contract)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "slither/tools/flattening/__main__.py"}, {"content": "from pathlib import Path\nimport re\nimport logging\nfrom collections import namedtuple\n\nfrom slither.core.declarations import SolidityFunction\nfrom slither.exceptions import SlitherException\nfrom slither.core.solidity_types.user_defined_type import UserDefinedType\nfrom slither.core.declarations.structure import Structure\nfrom slither.core.declarations.enum import Enum\nfrom slither.core.declarations.contract import Contract\nfrom slither.slithir.operations import NewContract, TypeConversion, SolidityCall\n\nlogger = logging.getLogger(\"Slither-flattening\")\n\n# index: where to start\n# patch_type:\n#   - public_to_external: public to external (external-to-public)\n#   - calldata_to_memory: calldata to memory (external-to-public)\n#   - line_removal: remove the line (remove-assert)\nPatch = namedtuple('PatchExternal', ['index', 'patch_type'])\n\nclass Flattening:\n    DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')\n\n    def __init__(self, slither, external_to_public=False, remove_assert=False, private_to_internal=False):\n        self._source_codes = {}\n        self._slither = slither\n        self._external_to_public = external_to_public\n        self._remove_assert = remove_assert\n        self._use_abi_encoder_v2 = False\n        self._private_to_internal = private_to_internal\n\n        self._check_abi_encoder_v2()\n\n        for contract in slither.contracts:\n            self._get_source_code(contract)\n\n    def _check_abi_encoder_v2(self):\n        for p in self._slither.pragma_directives:\n            if 'ABIEncoderV2' in str(p.directive):\n                self._use_abi_encoder_v2 = True\n                return\n\n    def _get_source_code(self, contract):\n        src_mapping = contract.source_mapping\n        content = self._slither.source_code[src_mapping['filename_absolute']]\n        start = src_mapping['start']\n        end = src_mapping['start'] + src_mapping['length']\n\n        to_patch = []\n        # interface must use external\n        if self._external_to_public and contract.contract_kind != \"interface\":\n            for f in contract.functions_declared:\n                # fallback must be external\n                if f.is_fallback or f.is_constructor_variables:\n                    continue\n                if f.visibility == 'external':\n                    attributes_start = (f.parameters_src.source_mapping['start'] +\n                                        f.parameters_src.source_mapping['length'])\n                    attributes_end = f.returns_src.source_mapping['start']\n                    attributes = content[attributes_start:attributes_end]\n                    regex = re.search(r'((\\sexternal)\\s+)|(\\sexternal)$|(\\)external)$', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'public_to_external'))\n                    else:\n                        raise SlitherException(f'External keyword not found {f.name} {attributes}')\n\n                    for var in f.parameters:\n                        if var.location == \"calldata\":\n                            calldata_start = var.source_mapping['start']\n                            calldata_end = calldata_start + var.source_mapping['length']\n                            calldata_idx = content[calldata_start:calldata_end].find(' calldata ')\n                            to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))\n\n        if self._private_to_internal:\n            for variable in contract.state_variables_declared:\n                if variable.visibility == 'private':\n                    print(variable.source_mapping)\n                    attributes_start = variable.source_mapping['start']\n                    attributes_end = attributes_start + variable.source_mapping['length']\n                    attributes = content[attributes_start:attributes_end]\n                    print(attributes)\n                    regex = re.search(r' private ', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'private_to_internal'))\n                    else:\n                        raise SlitherException(f'private keyword not found {v.name} {attributes}')\n\n        if self._remove_assert:\n            for function in contract.functions_and_modifiers_declared:\n                for node in function.nodes:\n                    for ir in node.irs:\n                        if isinstance(ir, SolidityCall) and ir.function == SolidityFunction('assert(bool)'):\n                            to_patch.append(Patch(node.source_mapping['start'], 'line_removal'))\n                            logger.info(f'Code commented: {node.expression} ({node.source_mapping_str})')\n\n        to_patch.sort(key=lambda x: x.index, reverse=True)\n\n        content = content[start:end]\n        for patch in to_patch:\n            patch_type = patch.patch_type\n            index = patch.index\n            index = index - start\n            if patch_type == 'public_to_external':\n                content = content[:index] + 'public' + content[index + len('external'):]\n            if patch_type == 'private_to_internal':\n                content = content[:index] + 'internal' + content[index + len('private'):]\n            elif patch_type == 'calldata_to_memory':\n                content = content[:index] + 'memory' + content[index + len('calldata'):]\n            else:\n                assert patch_type == 'line_removal'\n                content = content[:index] + ' // ' + content[index:]\n\n        self._source_codes[contract] = content\n\n    def _export_from_type(self, t, contract, exported, list_contract):\n        if isinstance(t, UserDefinedType):\n            if isinstance(t.type, (Enum, Structure)):\n                if t.type.contract != contract and not t.type.contract in exported:\n                    self._export_contract(t.type.contract, exported, list_contract)\n            else:\n                assert isinstance(t.type, Contract)\n                if t.type != contract and not t.type in exported:\n                    self._export_contract(t.type, exported, list_contract)\n\n    def _export_contract(self, contract, exported, list_contract):\n        if contract.name in exported:\n            return\n        exported.add(contract.name)\n        for inherited in contract.inheritance:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts called\n        externals = contract.all_library_calls + contract.all_high_level_calls\n        # externals is a list of (contract, function)\n        # We also filter call to itself to avoid infilite loop\n        externals = list(set([e[0] for e in externals if e[0] != contract]))\n\n        for inherited in externals:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts use as a base type\n        local_vars = []\n        for f in contract.functions_declared:\n            local_vars += f.variables\n\n        for v in contract.variables + local_vars:\n            self._export_from_type(v.type, contract, exported, list_contract)\n\n        # Find all convert and \"new\" operation that can lead to use an external contract\n        for f in contract.functions_declared:\n            for ir in f.slithir_operations:\n                if isinstance(ir, NewContract):\n                    if ir.contract_created != contract and not ir.contract_created in exported:\n                        self._export_contract(ir.contract_created, exported, list_contract)\n                if isinstance(ir, TypeConversion):\n                    self._export_from_type(ir.type, contract, exported, list_contract)\n        list_contract.append(self._source_codes[contract])\n\n    def _export(self, contract, ret):\n        self._export_contract(contract, set(), ret)\n        path = Path(self.DEFAULT_EXPORT_PATH, f'{contract.name}.sol')\n        logger.info(f'Export {path}')\n        with open(path, 'w') as f:\n            if self._slither.solc_version:\n                f.write(f'pragma solidity {self._slither.solc_version};\\n')\n            if self._use_abi_encoder_v2:\n                f.write('pragma experimental ABIEncoderV2;\\n')\n            f.write('\\n'.join(ret))\n            f.write('\\n')\n\n    def export(self, target=None):\n\n        if not self.DEFAULT_EXPORT_PATH.exists():\n            self.DEFAULT_EXPORT_PATH.mkdir(parents=True)\n\n        if target is None:\n            for contract in self._slither.contracts_derived:\n                ret = []\n                self._export(contract, ret)\n        else:\n            contract = self._slither.get_contract_from_name(target)\n            if contract is None:\n                logger.error(f'{target} not found')\n            else:\n                ret = []\n                self._export(contract, ret)\n", "path": "slither/tools/flattening/flattening.py"}]}