slither.core.compilation_unit

  1import math
  2from enum import Enum
  3from typing import TYPE_CHECKING
  4
  5from crytic_compile import CompilationUnit, CryticCompile
  6from crytic_compile.compiler.compiler import CompilerVersion
  7from crytic_compile.utils.naming import Filename
  8
  9from slither.core.context.context import Context
 10from slither.core.declarations import (
 11    Contract,
 12    Pragma,
 13    Import,
 14    Function,
 15    Modifier,
 16)
 17from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel
 18from slither.core.declarations.enum_top_level import EnumTopLevel
 19from slither.core.declarations.event_top_level import EventTopLevel
 20from slither.core.declarations.function_top_level import FunctionTopLevel
 21from slither.core.declarations.structure_top_level import StructureTopLevel
 22from slither.core.declarations.using_for_top_level import UsingForTopLevel
 23from slither.core.scope.scope import FileScope
 24from slither.core.solidity_types.type_alias import TypeAliasTopLevel
 25from slither.core.variables.state_variable import StateVariable
 26from slither.core.variables.top_level_variable import TopLevelVariable
 27from slither.slithir.operations import InternalCall
 28from slither.slithir.variables import Constant
 29
 30if TYPE_CHECKING:
 31    from slither.core.slither_core import SlitherCore
 32
 33
 34class Language(Enum):
 35    SOLIDITY = "solidity"
 36    VYPER = "vyper"
 37
 38    @staticmethod
 39    def from_str(label: str):
 40        if label == "solc":
 41            return Language.SOLIDITY
 42        if label == "vyper":
 43            return Language.VYPER
 44
 45        raise ValueError(f"Unknown language: {label}")
 46
 47
 48class SlitherCompilationUnit(Context):
 49    def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None:
 50        super().__init__()
 51
 52        self._core = core
 53        self._crytic_compile_compilation_unit = crytic_compilation_unit
 54        self._language = Language.from_str(crytic_compilation_unit.compiler_version.compiler)
 55
 56        # Top level object
 57        self.contracts: list[Contract] = []
 58        self._structures_top_level: list[StructureTopLevel] = []
 59        self._enums_top_level: list[EnumTopLevel] = []
 60        self._events_top_level: list[EventTopLevel] = []
 61        self._variables_top_level: list[TopLevelVariable] = []
 62        self._functions_top_level: list[FunctionTopLevel] = []
 63        self._using_for_top_level: list[UsingForTopLevel] = []
 64        self._pragma_directives: list[Pragma] = []
 65        self._import_directives: list[Import] = []
 66        self._custom_errors: list[CustomErrorTopLevel] = []
 67        self._type_aliases: dict[str, TypeAliasTopLevel] = {}
 68
 69        self._all_functions: set[Function] = set()
 70        self._all_modifiers: set[Modifier] = set()
 71
 72        # Memoize
 73        self._all_state_variables: set[StateVariable] | None = None
 74
 75        self._persistent_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {}
 76        self._transient_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {}
 77
 78        self._contract_with_missing_inheritance: set[Contract] = set()
 79
 80        # Reverse inheritance map: parent -> list of all derived contracts
 81        self._derived_contracts_map: dict[Contract, list[Contract]] | None = None
 82
 83        self._source_units: dict[int, str] = {}
 84
 85        self.counter_slithir_tuple = 0
 86        self.counter_slithir_temporary = 0
 87        self.counter_slithir_reference = 0
 88
 89        self.scopes: dict[Filename, FileScope] = {}
 90
 91        # Cache for filename lookups: file_index -> (Filename, is_dependency)
 92        # Used by _convert_source_mapping to avoid repeated expensive lookups
 93        self._filename_lookup_cache: dict[int, tuple[Filename, bool]] = {}
 94
 95    @property
 96    def core(self) -> "SlitherCore":
 97        return self._core
 98
 99    @property
100    def source_units(self) -> dict[int, str]:
101        return self._source_units
102
103    # endregion
104    ###################################################################################
105    ###################################################################################
106    # region Compiler
107    ###################################################################################
108    ###################################################################################
109    @property
110    def language(self) -> Language:
111        return self._language
112
113    @property
114    def is_vyper(self) -> bool:
115        return self._language == Language.VYPER
116
117    @property
118    def is_solidity(self) -> bool:
119        return self._language == Language.SOLIDITY
120
121    @property
122    def compiler_version(self) -> CompilerVersion:
123        return self._crytic_compile_compilation_unit.compiler_version
124
125    @property
126    def solc_version(self) -> str:
127        # TODO: make version a non optional argument of compiler version in cc
128        return self._crytic_compile_compilation_unit.compiler_version.version  # type:ignore
129
130    @property
131    def crytic_compile_compilation_unit(self) -> CompilationUnit:
132        return self._crytic_compile_compilation_unit
133
134    @property
135    def crytic_compile(self) -> CryticCompile:
136        return self._crytic_compile_compilation_unit.crytic_compile
137
138    # endregion
139    ###################################################################################
140    ###################################################################################
141    # region Pragma attributes
142    ###################################################################################
143    ###################################################################################
144
145    @property
146    def pragma_directives(self) -> list[Pragma]:
147        """list(core.declarations.Pragma): Pragma directives."""
148        return self._pragma_directives
149
150    @property
151    def import_directives(self) -> list[Import]:
152        """list(core.declarations.Import): Import directives"""
153        return self._import_directives
154
155    # endregion
156    ###################################################################################
157    ###################################################################################
158    # region Contracts
159    ###################################################################################
160    ###################################################################################
161
162    @property
163    def contracts_derived(self) -> list[Contract]:
164        """list(Contract): List of contracts that are derived and not inherited."""
165        inheritances = [x.inheritance for x in self.contracts]
166        inheritance = [item for sublist in inheritances for item in sublist]
167        return [c for c in self.contracts if c not in inheritance]
168
169    def get_contract_from_name(self, contract_name: str | Constant) -> list[Contract]:
170        """
171            Return a list of contract from a name
172        Args:
173            contract_name (str): name of the contract
174        Returns:
175            List[Contract]
176        """
177        return [c for c in self.contracts if c.name == contract_name]
178
179    # endregion
180    ###################################################################################
181    ###################################################################################
182    # region Functions and modifiers
183    ###################################################################################
184    ###################################################################################
185
186    @property
187    def functions(self) -> list[Function]:
188        return list(self._all_functions)
189
190    def add_function(self, func: Function) -> None:
191        self._all_functions.add(func)
192
193    @property
194    def modifiers(self) -> list[Modifier]:
195        return list(self._all_modifiers)
196
197    def add_modifier(self, modif: Modifier) -> None:
198        self._all_modifiers.add(modif)
199
200    @property
201    def functions_and_modifiers(self) -> list[Function]:
202        return self.functions + list(self.modifiers)
203
204    def propagate_function_calls(self) -> None:
205        """This info is used to compute the rvalues of Phi operations in `fix_phi` and ultimately
206        is responsible for the `read` property of Phi operations which is vital to
207        propagating taints inter-procedurally
208        """
209        for f in self.functions_and_modifiers:
210            for node in f.nodes:
211                for ir in node.irs_ssa:
212                    if isinstance(ir, InternalCall):
213                        assert ir.function
214                        ir.function.add_reachable_from_node(node, ir)
215
216    # endregion
217    ###################################################################################
218    ###################################################################################
219    # region Variables
220    ###################################################################################
221    ###################################################################################
222
223    @property
224    def state_variables(self) -> list[StateVariable]:
225        if self._all_state_variables is None:
226            state_variabless = [c.state_variables for c in self.contracts]
227            state_variables = [item for sublist in state_variabless for item in sublist]
228            self._all_state_variables = set(state_variables)
229        return list(self._all_state_variables)
230
231    # endregion
232    ###################################################################################
233    ###################################################################################
234    # region Top level
235    ###################################################################################
236    ###################################################################################
237
238    @property
239    def structures_top_level(self) -> list[StructureTopLevel]:
240        return self._structures_top_level
241
242    @property
243    def enums_top_level(self) -> list[EnumTopLevel]:
244        return self._enums_top_level
245
246    @property
247    def events_top_level(self) -> list[EventTopLevel]:
248        return self._events_top_level
249
250    @property
251    def variables_top_level(self) -> list[TopLevelVariable]:
252        return self._variables_top_level
253
254    @property
255    def functions_top_level(self) -> list[FunctionTopLevel]:
256        return self._functions_top_level
257
258    @property
259    def using_for_top_level(self) -> list[UsingForTopLevel]:
260        return self._using_for_top_level
261
262    @property
263    def custom_errors(self) -> list[CustomErrorTopLevel]:
264        return self._custom_errors
265
266    @property
267    def type_aliases(self) -> dict[str, TypeAliasTopLevel]:
268        return self._type_aliases
269
270    # endregion
271    ###################################################################################
272    ###################################################################################
273    # region Internals
274    ###################################################################################
275    ###################################################################################
276
277    @property
278    def contracts_with_missing_inheritance(self) -> set[Contract]:
279        return self._contract_with_missing_inheritance
280
281    def _build_derived_contracts_map(self) -> dict[Contract, list[Contract]]:
282        """Build reverse inheritance mapping for O(1) derived_contracts lookup."""
283        from collections import defaultdict
284
285        derived_map: dict[Contract, list[Contract]] = defaultdict(list)
286        for contract in self.contracts:
287            for parent in contract.inheritance:
288                if contract not in derived_map[parent]:
289                    derived_map[parent].append(contract)
290        return dict(derived_map)
291
292    @property
293    def derived_contracts_map(self) -> dict[Contract, list[Contract]]:
294        """Cached reverse inheritance map: parent contract -> list of all derived contracts."""
295        if self._derived_contracts_map is None:
296            self._derived_contracts_map = self._build_derived_contracts_map()
297        return self._derived_contracts_map
298
299    # endregion
300    ###################################################################################
301    ###################################################################################
302    # region Scope
303    ###################################################################################
304    ###################################################################################
305
306    def get_scope(self, filename_str: str) -> FileScope:
307        filename = self._crytic_compile_compilation_unit.crytic_compile.filename_lookup(
308            filename_str
309        )
310
311        if filename not in self.scopes:
312            self.scopes[filename] = FileScope(filename)
313
314        return self.scopes[filename]
315
316    # endregion
317    ###################################################################################
318    ###################################################################################
319    # region Storage Layouts
320    ###################################################################################
321    ###################################################################################
322
323    def compute_storage_layout(self) -> None:
324        assert self.is_solidity
325
326        for contract in self.contracts_derived:
327            self._compute_storage_layout(
328                contract.name,
329                contract.storage_variables_ordered,
330                False,
331                contract.custom_storage_layout,
332            )
333            self._compute_storage_layout(
334                contract.name, contract.transient_variables_ordered, True, None
335            )
336
337    def _compute_storage_layout(
338        self,
339        contract_name: str,
340        state_variables_ordered: list[StateVariable],
341        is_transient: bool,
342        custom_storage_layout: int | None,
343    ):
344        if is_transient:
345            slot = 0
346            self._transient_storage_layouts[contract_name] = {}
347        else:
348            slot = custom_storage_layout if custom_storage_layout else 0
349            self._persistent_storage_layouts[contract_name] = {}
350
351        offset = 0
352        for var in state_variables_ordered:
353            assert var.type
354            size, new_slot = var.type.storage_size
355
356            if new_slot:
357                if offset > 0:
358                    slot += 1
359                    offset = 0
360            elif size + offset > 32:
361                slot += 1
362                offset = 0
363
364            if is_transient:
365                self._transient_storage_layouts[contract_name][var.canonical_name] = (
366                    slot,
367                    offset,
368                )
369            else:
370                self._persistent_storage_layouts[contract_name][var.canonical_name] = (
371                    slot,
372                    offset,
373                )
374
375            if new_slot:
376                slot += math.ceil(size / 32)
377            else:
378                offset += size
379
380    def storage_layout_of(self, contract: Contract, var: StateVariable) -> tuple[int, int]:
381        if var.is_stored:
382            return self._persistent_storage_layouts[contract.name][var.canonical_name]
383        return self._transient_storage_layouts[contract.name][var.canonical_name]
384
385    # endregion
class Language(enum.Enum):
35class Language(Enum):
36    SOLIDITY = "solidity"
37    VYPER = "vyper"
38
39    @staticmethod
40    def from_str(label: str):
41        if label == "solc":
42            return Language.SOLIDITY
43        if label == "vyper":
44            return Language.VYPER
45
46        raise ValueError(f"Unknown language: {label}")

An enumeration.

SOLIDITY = <Language.SOLIDITY: 'solidity'>
VYPER = <Language.VYPER: 'vyper'>
@staticmethod
def from_str(label: str):
39    @staticmethod
40    def from_str(label: str):
41        if label == "solc":
42            return Language.SOLIDITY
43        if label == "vyper":
44            return Language.VYPER
45
46        raise ValueError(f"Unknown language: {label}")
class SlitherCompilationUnit(slither.core.context.context.Context):
 49class SlitherCompilationUnit(Context):
 50    def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None:
 51        super().__init__()
 52
 53        self._core = core
 54        self._crytic_compile_compilation_unit = crytic_compilation_unit
 55        self._language = Language.from_str(crytic_compilation_unit.compiler_version.compiler)
 56
 57        # Top level object
 58        self.contracts: list[Contract] = []
 59        self._structures_top_level: list[StructureTopLevel] = []
 60        self._enums_top_level: list[EnumTopLevel] = []
 61        self._events_top_level: list[EventTopLevel] = []
 62        self._variables_top_level: list[TopLevelVariable] = []
 63        self._functions_top_level: list[FunctionTopLevel] = []
 64        self._using_for_top_level: list[UsingForTopLevel] = []
 65        self._pragma_directives: list[Pragma] = []
 66        self._import_directives: list[Import] = []
 67        self._custom_errors: list[CustomErrorTopLevel] = []
 68        self._type_aliases: dict[str, TypeAliasTopLevel] = {}
 69
 70        self._all_functions: set[Function] = set()
 71        self._all_modifiers: set[Modifier] = set()
 72
 73        # Memoize
 74        self._all_state_variables: set[StateVariable] | None = None
 75
 76        self._persistent_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {}
 77        self._transient_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {}
 78
 79        self._contract_with_missing_inheritance: set[Contract] = set()
 80
 81        # Reverse inheritance map: parent -> list of all derived contracts
 82        self._derived_contracts_map: dict[Contract, list[Contract]] | None = None
 83
 84        self._source_units: dict[int, str] = {}
 85
 86        self.counter_slithir_tuple = 0
 87        self.counter_slithir_temporary = 0
 88        self.counter_slithir_reference = 0
 89
 90        self.scopes: dict[Filename, FileScope] = {}
 91
 92        # Cache for filename lookups: file_index -> (Filename, is_dependency)
 93        # Used by _convert_source_mapping to avoid repeated expensive lookups
 94        self._filename_lookup_cache: dict[int, tuple[Filename, bool]] = {}
 95
 96    @property
 97    def core(self) -> "SlitherCore":
 98        return self._core
 99
100    @property
101    def source_units(self) -> dict[int, str]:
102        return self._source_units
103
104    # endregion
105    ###################################################################################
106    ###################################################################################
107    # region Compiler
108    ###################################################################################
109    ###################################################################################
110    @property
111    def language(self) -> Language:
112        return self._language
113
114    @property
115    def is_vyper(self) -> bool:
116        return self._language == Language.VYPER
117
118    @property
119    def is_solidity(self) -> bool:
120        return self._language == Language.SOLIDITY
121
122    @property
123    def compiler_version(self) -> CompilerVersion:
124        return self._crytic_compile_compilation_unit.compiler_version
125
126    @property
127    def solc_version(self) -> str:
128        # TODO: make version a non optional argument of compiler version in cc
129        return self._crytic_compile_compilation_unit.compiler_version.version  # type:ignore
130
131    @property
132    def crytic_compile_compilation_unit(self) -> CompilationUnit:
133        return self._crytic_compile_compilation_unit
134
135    @property
136    def crytic_compile(self) -> CryticCompile:
137        return self._crytic_compile_compilation_unit.crytic_compile
138
139    # endregion
140    ###################################################################################
141    ###################################################################################
142    # region Pragma attributes
143    ###################################################################################
144    ###################################################################################
145
146    @property
147    def pragma_directives(self) -> list[Pragma]:
148        """list(core.declarations.Pragma): Pragma directives."""
149        return self._pragma_directives
150
151    @property
152    def import_directives(self) -> list[Import]:
153        """list(core.declarations.Import): Import directives"""
154        return self._import_directives
155
156    # endregion
157    ###################################################################################
158    ###################################################################################
159    # region Contracts
160    ###################################################################################
161    ###################################################################################
162
163    @property
164    def contracts_derived(self) -> list[Contract]:
165        """list(Contract): List of contracts that are derived and not inherited."""
166        inheritances = [x.inheritance for x in self.contracts]
167        inheritance = [item for sublist in inheritances for item in sublist]
168        return [c for c in self.contracts if c not in inheritance]
169
170    def get_contract_from_name(self, contract_name: str | Constant) -> list[Contract]:
171        """
172            Return a list of contract from a name
173        Args:
174            contract_name (str): name of the contract
175        Returns:
176            List[Contract]
177        """
178        return [c for c in self.contracts if c.name == contract_name]
179
180    # endregion
181    ###################################################################################
182    ###################################################################################
183    # region Functions and modifiers
184    ###################################################################################
185    ###################################################################################
186
187    @property
188    def functions(self) -> list[Function]:
189        return list(self._all_functions)
190
191    def add_function(self, func: Function) -> None:
192        self._all_functions.add(func)
193
194    @property
195    def modifiers(self) -> list[Modifier]:
196        return list(self._all_modifiers)
197
198    def add_modifier(self, modif: Modifier) -> None:
199        self._all_modifiers.add(modif)
200
201    @property
202    def functions_and_modifiers(self) -> list[Function]:
203        return self.functions + list(self.modifiers)
204
205    def propagate_function_calls(self) -> None:
206        """This info is used to compute the rvalues of Phi operations in `fix_phi` and ultimately
207        is responsible for the `read` property of Phi operations which is vital to
208        propagating taints inter-procedurally
209        """
210        for f in self.functions_and_modifiers:
211            for node in f.nodes:
212                for ir in node.irs_ssa:
213                    if isinstance(ir, InternalCall):
214                        assert ir.function
215                        ir.function.add_reachable_from_node(node, ir)
216
217    # endregion
218    ###################################################################################
219    ###################################################################################
220    # region Variables
221    ###################################################################################
222    ###################################################################################
223
224    @property
225    def state_variables(self) -> list[StateVariable]:
226        if self._all_state_variables is None:
227            state_variabless = [c.state_variables for c in self.contracts]
228            state_variables = [item for sublist in state_variabless for item in sublist]
229            self._all_state_variables = set(state_variables)
230        return list(self._all_state_variables)
231
232    # endregion
233    ###################################################################################
234    ###################################################################################
235    # region Top level
236    ###################################################################################
237    ###################################################################################
238
239    @property
240    def structures_top_level(self) -> list[StructureTopLevel]:
241        return self._structures_top_level
242
243    @property
244    def enums_top_level(self) -> list[EnumTopLevel]:
245        return self._enums_top_level
246
247    @property
248    def events_top_level(self) -> list[EventTopLevel]:
249        return self._events_top_level
250
251    @property
252    def variables_top_level(self) -> list[TopLevelVariable]:
253        return self._variables_top_level
254
255    @property
256    def functions_top_level(self) -> list[FunctionTopLevel]:
257        return self._functions_top_level
258
259    @property
260    def using_for_top_level(self) -> list[UsingForTopLevel]:
261        return self._using_for_top_level
262
263    @property
264    def custom_errors(self) -> list[CustomErrorTopLevel]:
265        return self._custom_errors
266
267    @property
268    def type_aliases(self) -> dict[str, TypeAliasTopLevel]:
269        return self._type_aliases
270
271    # endregion
272    ###################################################################################
273    ###################################################################################
274    # region Internals
275    ###################################################################################
276    ###################################################################################
277
278    @property
279    def contracts_with_missing_inheritance(self) -> set[Contract]:
280        return self._contract_with_missing_inheritance
281
282    def _build_derived_contracts_map(self) -> dict[Contract, list[Contract]]:
283        """Build reverse inheritance mapping for O(1) derived_contracts lookup."""
284        from collections import defaultdict
285
286        derived_map: dict[Contract, list[Contract]] = defaultdict(list)
287        for contract in self.contracts:
288            for parent in contract.inheritance:
289                if contract not in derived_map[parent]:
290                    derived_map[parent].append(contract)
291        return dict(derived_map)
292
293    @property
294    def derived_contracts_map(self) -> dict[Contract, list[Contract]]:
295        """Cached reverse inheritance map: parent contract -> list of all derived contracts."""
296        if self._derived_contracts_map is None:
297            self._derived_contracts_map = self._build_derived_contracts_map()
298        return self._derived_contracts_map
299
300    # endregion
301    ###################################################################################
302    ###################################################################################
303    # region Scope
304    ###################################################################################
305    ###################################################################################
306
307    def get_scope(self, filename_str: str) -> FileScope:
308        filename = self._crytic_compile_compilation_unit.crytic_compile.filename_lookup(
309            filename_str
310        )
311
312        if filename not in self.scopes:
313            self.scopes[filename] = FileScope(filename)
314
315        return self.scopes[filename]
316
317    # endregion
318    ###################################################################################
319    ###################################################################################
320    # region Storage Layouts
321    ###################################################################################
322    ###################################################################################
323
324    def compute_storage_layout(self) -> None:
325        assert self.is_solidity
326
327        for contract in self.contracts_derived:
328            self._compute_storage_layout(
329                contract.name,
330                contract.storage_variables_ordered,
331                False,
332                contract.custom_storage_layout,
333            )
334            self._compute_storage_layout(
335                contract.name, contract.transient_variables_ordered, True, None
336            )
337
338    def _compute_storage_layout(
339        self,
340        contract_name: str,
341        state_variables_ordered: list[StateVariable],
342        is_transient: bool,
343        custom_storage_layout: int | None,
344    ):
345        if is_transient:
346            slot = 0
347            self._transient_storage_layouts[contract_name] = {}
348        else:
349            slot = custom_storage_layout if custom_storage_layout else 0
350            self._persistent_storage_layouts[contract_name] = {}
351
352        offset = 0
353        for var in state_variables_ordered:
354            assert var.type
355            size, new_slot = var.type.storage_size
356
357            if new_slot:
358                if offset > 0:
359                    slot += 1
360                    offset = 0
361            elif size + offset > 32:
362                slot += 1
363                offset = 0
364
365            if is_transient:
366                self._transient_storage_layouts[contract_name][var.canonical_name] = (
367                    slot,
368                    offset,
369                )
370            else:
371                self._persistent_storage_layouts[contract_name][var.canonical_name] = (
372                    slot,
373                    offset,
374                )
375
376            if new_slot:
377                slot += math.ceil(size / 32)
378            else:
379                offset += size
380
381    def storage_layout_of(self, contract: Contract, var: StateVariable) -> tuple[int, int]:
382        if var.is_stored:
383            return self._persistent_storage_layouts[contract.name][var.canonical_name]
384        return self._transient_storage_layouts[contract.name][var.canonical_name]
385
386    # endregion
SlitherCompilationUnit( core: slither.core.slither_core.SlitherCore, crytic_compilation_unit: crytic_compile.compilation_unit.CompilationUnit)
50    def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None:
51        super().__init__()
52
53        self._core = core
54        self._crytic_compile_compilation_unit = crytic_compilation_unit
55        self._language = Language.from_str(crytic_compilation_unit.compiler_version.compiler)
56
57        # Top level object
58        self.contracts: list[Contract] = []
59        self._structures_top_level: list[StructureTopLevel] = []
60        self._enums_top_level: list[EnumTopLevel] = []
61        self._events_top_level: list[EventTopLevel] = []
62        self._variables_top_level: list[TopLevelVariable] = []
63        self._functions_top_level: list[FunctionTopLevel] = []
64        self._using_for_top_level: list[UsingForTopLevel] = []
65        self._pragma_directives: list[Pragma] = []
66        self._import_directives: list[Import] = []
67        self._custom_errors: list[CustomErrorTopLevel] = []
68        self._type_aliases: dict[str, TypeAliasTopLevel] = {}
69
70        self._all_functions: set[Function] = set()
71        self._all_modifiers: set[Modifier] = set()
72
73        # Memoize
74        self._all_state_variables: set[StateVariable] | None = None
75
76        self._persistent_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {}
77        self._transient_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {}
78
79        self._contract_with_missing_inheritance: set[Contract] = set()
80
81        # Reverse inheritance map: parent -> list of all derived contracts
82        self._derived_contracts_map: dict[Contract, list[Contract]] | None = None
83
84        self._source_units: dict[int, str] = {}
85
86        self.counter_slithir_tuple = 0
87        self.counter_slithir_temporary = 0
88        self.counter_slithir_reference = 0
89
90        self.scopes: dict[Filename, FileScope] = {}
91
92        # Cache for filename lookups: file_index -> (Filename, is_dependency)
93        # Used by _convert_source_mapping to avoid repeated expensive lookups
94        self._filename_lookup_cache: dict[int, tuple[Filename, bool]] = {}
counter_slithir_tuple
counter_slithir_temporary
counter_slithir_reference
scopes: dict[crytic_compile.utils.naming.Filename, slither.core.scope.scope.FileScope]
96    @property
97    def core(self) -> "SlitherCore":
98        return self._core
source_units: dict[int, str]
100    @property
101    def source_units(self) -> dict[int, str]:
102        return self._source_units
language: Language
110    @property
111    def language(self) -> Language:
112        return self._language
is_vyper: bool
114    @property
115    def is_vyper(self) -> bool:
116        return self._language == Language.VYPER
is_solidity: bool
118    @property
119    def is_solidity(self) -> bool:
120        return self._language == Language.SOLIDITY
compiler_version: crytic_compile.compiler.compiler.CompilerVersion
122    @property
123    def compiler_version(self) -> CompilerVersion:
124        return self._crytic_compile_compilation_unit.compiler_version
solc_version: str
126    @property
127    def solc_version(self) -> str:
128        # TODO: make version a non optional argument of compiler version in cc
129        return self._crytic_compile_compilation_unit.compiler_version.version  # type:ignore
crytic_compile_compilation_unit: crytic_compile.compilation_unit.CompilationUnit
131    @property
132    def crytic_compile_compilation_unit(self) -> CompilationUnit:
133        return self._crytic_compile_compilation_unit
crytic_compile: crytic_compile.crytic_compile.CryticCompile
135    @property
136    def crytic_compile(self) -> CryticCompile:
137        return self._crytic_compile_compilation_unit.crytic_compile
pragma_directives: list[slither.core.declarations.pragma_directive.Pragma]
146    @property
147    def pragma_directives(self) -> list[Pragma]:
148        """list(core.declarations.Pragma): Pragma directives."""
149        return self._pragma_directives

list(core.declarations.Pragma): Pragma directives.

import_directives: list[slither.core.declarations.import_directive.Import]
151    @property
152    def import_directives(self) -> list[Import]:
153        """list(core.declarations.Import): Import directives"""
154        return self._import_directives

list(core.declarations.Import): Import directives

contracts_derived: list[slither.core.declarations.contract.Contract]
163    @property
164    def contracts_derived(self) -> list[Contract]:
165        """list(Contract): List of contracts that are derived and not inherited."""
166        inheritances = [x.inheritance for x in self.contracts]
167        inheritance = [item for sublist in inheritances for item in sublist]
168        return [c for c in self.contracts if c not in inheritance]

list(Contract): List of contracts that are derived and not inherited.

def get_contract_from_name( self, contract_name: str | slither.slithir.variables.constant.Constant) -> list[slither.core.declarations.contract.Contract]:
170    def get_contract_from_name(self, contract_name: str | Constant) -> list[Contract]:
171        """
172            Return a list of contract from a name
173        Args:
174            contract_name (str): name of the contract
175        Returns:
176            List[Contract]
177        """
178        return [c for c in self.contracts if c.name == contract_name]

Return a list of contract from a name Args: contract_name (str): name of the contract Returns: List[Contract]

functions: list[slither.core.declarations.function.Function]
187    @property
188    def functions(self) -> list[Function]:
189        return list(self._all_functions)
def add_function(self, func: slither.core.declarations.function.Function) -> None:
191    def add_function(self, func: Function) -> None:
192        self._all_functions.add(func)
modifiers: list[slither.core.declarations.modifier.Modifier]
194    @property
195    def modifiers(self) -> list[Modifier]:
196        return list(self._all_modifiers)
def add_modifier(self, modif: slither.core.declarations.modifier.Modifier) -> None:
198    def add_modifier(self, modif: Modifier) -> None:
199        self._all_modifiers.add(modif)
functions_and_modifiers: list[slither.core.declarations.function.Function]
201    @property
202    def functions_and_modifiers(self) -> list[Function]:
203        return self.functions + list(self.modifiers)
def propagate_function_calls(self) -> None:
205    def propagate_function_calls(self) -> None:
206        """This info is used to compute the rvalues of Phi operations in `fix_phi` and ultimately
207        is responsible for the `read` property of Phi operations which is vital to
208        propagating taints inter-procedurally
209        """
210        for f in self.functions_and_modifiers:
211            for node in f.nodes:
212                for ir in node.irs_ssa:
213                    if isinstance(ir, InternalCall):
214                        assert ir.function
215                        ir.function.add_reachable_from_node(node, ir)

This info is used to compute the rvalues of Phi operations in fix_phi and ultimately is responsible for the read property of Phi operations which is vital to propagating taints inter-procedurally

state_variables: list[slither.core.variables.state_variable.StateVariable]
224    @property
225    def state_variables(self) -> list[StateVariable]:
226        if self._all_state_variables is None:
227            state_variabless = [c.state_variables for c in self.contracts]
228            state_variables = [item for sublist in state_variabless for item in sublist]
229            self._all_state_variables = set(state_variables)
230        return list(self._all_state_variables)
structures_top_level: list[slither.core.declarations.structure_top_level.StructureTopLevel]
239    @property
240    def structures_top_level(self) -> list[StructureTopLevel]:
241        return self._structures_top_level
enums_top_level: list[slither.core.declarations.enum_top_level.EnumTopLevel]
243    @property
244    def enums_top_level(self) -> list[EnumTopLevel]:
245        return self._enums_top_level
events_top_level: list[slither.core.declarations.event_top_level.EventTopLevel]
247    @property
248    def events_top_level(self) -> list[EventTopLevel]:
249        return self._events_top_level
variables_top_level: list[slither.core.variables.top_level_variable.TopLevelVariable]
251    @property
252    def variables_top_level(self) -> list[TopLevelVariable]:
253        return self._variables_top_level
functions_top_level: list[slither.core.declarations.function_top_level.FunctionTopLevel]
255    @property
256    def functions_top_level(self) -> list[FunctionTopLevel]:
257        return self._functions_top_level
259    @property
260    def using_for_top_level(self) -> list[UsingForTopLevel]:
261        return self._using_for_top_level
263    @property
264    def custom_errors(self) -> list[CustomErrorTopLevel]:
265        return self._custom_errors
type_aliases: dict[str, slither.core.solidity_types.type_alias.TypeAliasTopLevel]
267    @property
268    def type_aliases(self) -> dict[str, TypeAliasTopLevel]:
269        return self._type_aliases
contracts_with_missing_inheritance: set[slither.core.declarations.contract.Contract]
278    @property
279    def contracts_with_missing_inheritance(self) -> set[Contract]:
280        return self._contract_with_missing_inheritance
293    @property
294    def derived_contracts_map(self) -> dict[Contract, list[Contract]]:
295        """Cached reverse inheritance map: parent contract -> list of all derived contracts."""
296        if self._derived_contracts_map is None:
297            self._derived_contracts_map = self._build_derived_contracts_map()
298        return self._derived_contracts_map

Cached reverse inheritance map: parent contract -> list of all derived contracts.

def get_scope(self, filename_str: str) -> slither.core.scope.scope.FileScope:
307    def get_scope(self, filename_str: str) -> FileScope:
308        filename = self._crytic_compile_compilation_unit.crytic_compile.filename_lookup(
309            filename_str
310        )
311
312        if filename not in self.scopes:
313            self.scopes[filename] = FileScope(filename)
314
315        return self.scopes[filename]
def compute_storage_layout(self) -> None:
324    def compute_storage_layout(self) -> None:
325        assert self.is_solidity
326
327        for contract in self.contracts_derived:
328            self._compute_storage_layout(
329                contract.name,
330                contract.storage_variables_ordered,
331                False,
332                contract.custom_storage_layout,
333            )
334            self._compute_storage_layout(
335                contract.name, contract.transient_variables_ordered, True, None
336            )
def storage_layout_of( self, contract: slither.core.declarations.contract.Contract, var: slither.core.variables.state_variable.StateVariable) -> tuple[int, int]:
381    def storage_layout_of(self, contract: Contract, var: StateVariable) -> tuple[int, int]:
382        if var.is_stored:
383            return self._persistent_storage_layouts[contract.name][var.canonical_name]
384        return self._transient_storage_layouts[contract.name][var.canonical_name]