diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 783acb0519..50eadeaa6b 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -460,6 +460,30 @@ def parse_contracts(self) -> None: if self._parsed: raise Exception("Contract analysis can be run only once!") + def resolve_contract_from_scope( + scope: FileScope, contract_name: str, seen: set[FileScope] | None = None + ) -> Contract | None: + seen = seen or set() + if scope in seen: + return None + seen.add(scope) + + target = scope.get_contract_from_name(contract_name) + if target is not None: + return target + + if contract_name in scope.renaming: + target = scope.get_contract_from_name(scope.renaming[contract_name]) + if target is not None: + return target + + for accessible_scope in scope.accessible_scopes: + target = resolve_contract_from_scope(accessible_scope, contract_name, seen) + if target is not None: + return target + + return None + def resolve_remapping_and_renaming(contract_parser: ContractSolc, want: str) -> Contract: contract_name = contract_parser.remapping[want] target = None @@ -475,8 +499,8 @@ def resolve_remapping_and_renaming(contract_parser: ContractSolc, want: str) -> # Fallback to the current file scope if the contract is not found in the import path's scope. # It is assumed that it isn't possible to defined a contract with the same name as "aliased" names. if target is None: - target = contract_parser.underlying_contract.file_scope.get_contract_from_name( - contract_name + target = resolve_contract_from_scope( + contract_parser.underlying_contract.file_scope, contract_name ) if target == contract_parser.underlying_contract: diff --git a/tests/e2e/solc_parsing/test_ast_parsing.py b/tests/e2e/solc_parsing/test_ast_parsing.py index 566766d788..2e03163c82 100644 --- a/tests/e2e/solc_parsing/test_ast_parsing.py +++ b/tests/e2e/solc_parsing/test_ast_parsing.py @@ -432,6 +432,7 @@ def make_version(minor: int, patch_min: int, patch_max: int) -> list[str]: ), Test("custom_error_with_state_variable.sol", make_version(8, 4, 12)), Test("complex_imports/import_aliases/test.sol", VERSIONS_08), + Test("complex_imports/import_aliases_reexport/test.sol", ["0.8.35"]), # 0.8.9 crashes on our testcase Test( "user_defined_value_type/user_defined_types-0.8.8.sol", ["0.8.8"] + make_version(8, 10, 15) diff --git a/tests/e2e/solc_parsing/test_data/compile/complex_imports/import_aliases_reexport/test.sol-0.8.35-compact.zip b/tests/e2e/solc_parsing/test_data/compile/complex_imports/import_aliases_reexport/test.sol-0.8.35-compact.zip new file mode 100644 index 0000000000..182f172d04 Binary files /dev/null and b/tests/e2e/solc_parsing/test_data/compile/complex_imports/import_aliases_reexport/test.sol-0.8.35-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/Alias.sol b/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/Alias.sol new file mode 100644 index 0000000000..c2d9f18e4c --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/Alias.sol @@ -0,0 +1 @@ +import {Original as Alias} from "./Original.sol"; diff --git a/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/Original.sol b/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/Original.sol new file mode 100644 index 0000000000..857836cc72 --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/Original.sol @@ -0,0 +1,3 @@ +interface Original { + function run() external; +} diff --git a/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/test.sol b/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/test.sol new file mode 100644 index 0000000000..b6f5fabd4f --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/complex_imports/import_aliases_reexport/test.sol @@ -0,0 +1,5 @@ +import "./Alias.sol"; + +contract Child is Alias { + function run() external override {} +} diff --git a/tests/e2e/solc_parsing/test_data/expected/complex_imports/import_aliases_reexport/test.sol-0.8.35-compact.json b/tests/e2e/solc_parsing/test_data/expected/complex_imports/import_aliases_reexport/test.sol-0.8.35-compact.json new file mode 100644 index 0000000000..7c4cd97aae --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/expected/complex_imports/import_aliases_reexport/test.sol-0.8.35-compact.json @@ -0,0 +1,8 @@ +{ + "Original": { + "run()": "digraph{\n}\n" + }, + "Child": { + "run()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file