diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 783acb0519..a66b488d60 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -462,6 +462,9 @@ def parse_contracts(self) -> None: def resolve_remapping_and_renaming(contract_parser: ContractSolc, want: str) -> Contract: contract_name = contract_parser.remapping[want] + contract_by_id = self._contracts_by_id.get(want) + if contract_by_id is not None and contract_by_id.name == contract_name: + return contract_by_id target = None # For contracts that are imported and aliased e.g. 'import {A as B} from "./C.sol"', # we look through the imports's (`Import`) renaming to find the original contract name diff --git a/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/BaseLock.sol b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/BaseLock.sol new file mode 100644 index 0000000000..f279467868 --- /dev/null +++ b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/BaseLock.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.8.0; + +abstract contract Lock {} diff --git a/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/IndirectBase.sol b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/IndirectBase.sol new file mode 100644 index 0000000000..eca4f0ffc7 --- /dev/null +++ b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/IndirectBase.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.8.0; + +import {Lock} from "./LockLibrary.sol"; + +abstract contract IndirectBase { + using Lock for uint256; +} diff --git a/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/LockLibrary.sol b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/LockLibrary.sol new file mode 100644 index 0000000000..1454b7dc35 --- /dev/null +++ b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/LockLibrary.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.8.0; + +library Lock { + function identity(uint256 value) internal pure returns (uint256) { + return value; + } +} diff --git a/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/Target.sol b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/Target.sol new file mode 100644 index 0000000000..9dcf223937 --- /dev/null +++ b/tests/unit/core/test_data/inheritance_resolution/transitive_duplicate_name/Target.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.8.0; + +import {Lock} from "./BaseLock.sol"; +import {IndirectBase} from "./IndirectBase.sol"; + +contract Target is IndirectBase, Lock {} diff --git a/tests/unit/core/test_inheritance.py b/tests/unit/core/test_inheritance.py index 8f5885a71b..279bcf2c17 100644 --- a/tests/unit/core/test_inheritance.py +++ b/tests/unit/core/test_inheritance.py @@ -42,3 +42,18 @@ def test_inheritance_with_duplicate_names(solc_binary_path) -> None: Path(TEST_DATA_DIR / "duplicate_names", "contract_with_duplicate_names.sol").as_posix(), solc=solc_path, ) + + +def test_inheritance_with_transitive_duplicate_name(solc_binary_path) -> None: + solc_path = solc_binary_path("0.8.15") + standard_json = SolcStandardJson() + for source_file in Path(TEST_DATA_DIR / "transitive_duplicate_name").rglob("*.sol"): + standard_json.add_source_file(source_file.as_posix()) + + slither = Slither(CryticCompile(standard_json, solc=solc_path), disallow_partial=True) + target = slither.get_contract_from_name("Target")[0] + + assert [(base.name, base.contract_kind) for base in target.inheritance] == [ + ("Lock", "contract"), + ("IndirectBase", "contract"), + ]