fix: support aliases for NewContract operation

pull/2370/head
alpharush 8 months ago
parent 6368368658
commit 69ece6da84
  1. 7
      slither/slithir/convert.py
  2. 14
      slither/slithir/operations/new_contract.py
  3. 17
      slither/solc_parsing/expressions/expression_parsing.py
  4. 2
      tests/e2e/solc_parsing/test_ast_parsing.py
  5. 8
      tests/e2e/solc_parsing/test_data/aliasing/alias-symbol-NewContract.sol
  6. 9
      tests/e2e/solc_parsing/test_data/aliasing/alias-unit-NewContract.sol
  7. BIN
      tests/e2e/solc_parsing/test_data/compile/aliasing/alias-symbol-NewContract.sol-0.8.19-compact.zip
  8. BIN
      tests/e2e/solc_parsing/test_data/compile/aliasing/alias-unit-NewContract.sol-0.8.19-compact.zip
  9. 6
      tests/e2e/solc_parsing/test_data/expected/aliasing/alias-symbol-NewContract.sol-0.8.19-compact.json
  10. 6
      tests/e2e/solc_parsing/test_data/expected/aliasing/alias-unit-NewContract.sol-0.8.19-compact.json

@ -871,9 +871,7 @@ def propagate_types(ir: Operation, node: "Node"): # pylint: disable=too-many-lo
elif isinstance(ir, NewArray):
ir.lvalue.set_type(ir.array_type)
elif isinstance(ir, NewContract):
contract = node.file_scope.get_contract_from_name(ir.contract_name)
assert contract
ir.lvalue.set_type(UserDefinedType(contract))
ir.lvalue.set_type(ir.contract_name)
elif isinstance(ir, NewElementaryType):
ir.lvalue.set_type(ir.type)
elif isinstance(ir, NewStructure):
@ -1164,7 +1162,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call,
return n
if isinstance(ins.ori, TmpNewContract):
op = NewContract(Constant(ins.ori.contract_name), ins.lvalue)
op = NewContract(ins.ori.contract_name, ins.lvalue)
op.set_expression(ins.expression)
op.call_id = ins.call_id
if ins.call_value:
@ -1719,6 +1717,7 @@ def convert_type_of_high_and_internal_level_call(
Returns:
Potential new IR
"""
func = None
if isinstance(ir, InternalCall):
candidates: List[Function]

@ -3,6 +3,7 @@ from typing import Optional, Any, List, Union
from slither.core.declarations import Function
from slither.core.declarations.contract import Contract
from slither.core.variables import Variable
from slither.core.solidity_types import UserDefinedType
from slither.slithir.operations import Call, OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue
from slither.slithir.variables.constant import Constant
@ -13,7 +14,7 @@ from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes
def __init__(
self,
contract_name: Constant,
contract_name: UserDefinedType,
lvalue: Union[TemporaryVariableSSA, TemporaryVariable],
names: Optional[List[str]] = None,
) -> None:
@ -23,7 +24,9 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instan
For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order.
Otherwise, None.
"""
assert isinstance(contract_name, Constant)
assert isinstance(
contract_name.type, Contract
), f"contract_name is {contract_name} of type {type(contract_name)}"
assert is_valid_lvalue(lvalue)
super().__init__(names=names)
self._contract_name = contract_name
@ -58,7 +61,7 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instan
self._call_salt = s
@property
def contract_name(self) -> Constant:
def contract_name(self) -> UserDefinedType:
return self._contract_name
@property
@ -69,10 +72,7 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instan
@property
def contract_created(self) -> Contract:
contract_name = self.contract_name
contract_instance = self.node.file_scope.get_contract_from_name(contract_name)
assert contract_instance
return contract_instance
return self.contract_name.type
###################################################################################
###################################################################################

@ -614,20 +614,9 @@ def parse_expression(expression: Dict, caller_context: CallerContextExpression)
assert type_name[caller_context.get_key()] == "UserDefinedTypeName"
if is_compact_ast:
# Changed introduced in Solidity 0.8
# see https://github.com/crytic/slither/issues/794
# TODO explore more the changes introduced in 0.8 and the usage of pathNode/IdentifierPath
if "name" not in type_name:
assert "pathNode" in type_name and "name" in type_name["pathNode"]
contract_name = type_name["pathNode"]["name"]
else:
contract_name = type_name["name"]
else:
contract_name = type_name["attributes"]["name"]
new = NewContract(contract_name)
contract_type = parse_type(type_name, caller_context)
assert isinstance(contract_type, UserDefinedType)
new = NewContract(contract_type)
new.set_offset(src, caller_context.compilation_unit)
return new

@ -467,6 +467,8 @@ ALL_TESTS = [
),
Test("user_defined_operators-0.8.19.sol", ["0.8.19"]),
Test("aliasing/main.sol", ["0.8.19"]),
Test("aliasing/alias-unit-NewContract.sol", ["0.8.19"]),
Test("aliasing/alias-symbol-NewContract.sol", ["0.8.19"]),
Test("type-aliases.sol", ["0.8.19"]),
Test("enum-max-min.sol", ["0.8.19"]),
Test("event-top-level.sol", ["0.8.22"]),

@ -0,0 +1,8 @@
import {MyContract as MyAliasedContract} from "./MyContract.sol";
contract Test {
MyAliasedContract c;
constructor() {
c = new MyAliasedContract();
}
}

@ -0,0 +1,9 @@
import "./MyContract.sol" as MyAliasedContract;
contract Test {
MyAliasedContract.MyContract c;
constructor() {
c = new MyAliasedContract.MyContract();
}
}

@ -0,0 +1,6 @@
{
"MyContract": {},
"Test": {
"constructor()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n"
}
}

@ -0,0 +1,6 @@
{
"MyContract": {},
"Test": {
"constructor()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n"
}
}
Loading…
Cancel
Save