Ejemplo n.º 1
0
def parse_type(t, caller_context):
    # local import to avoid circular dependency
    from slither.solc_parsing.expressions.expression_parsing import parse_expression
    from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc

    if isinstance(caller_context, Contract):
        contract = caller_context
    elif isinstance(caller_context, Function):
        contract = caller_context.contract
    else:
        raise ParsingError('Incorrect caller context')

    is_compact_ast = caller_context.is_compact_ast

    if is_compact_ast:
        key = 'nodeType'
    else:
        key = 'name'

    structures = contract.structures
    enums = contract.enums
    contracts = contract.slither.contracts

    if isinstance(t, UnknownType):
        return _find_from_type_name(t.name, contract, contracts, structures,
                                    enums)

    elif t[key] == 'ElementaryTypeName':
        if is_compact_ast:
            return ElementaryType(t['name'])
        return ElementaryType(t['attributes'][key])

    elif t[key] == 'UserDefinedTypeName':
        if is_compact_ast:
            return _find_from_type_name(t['typeDescriptions']['typeString'],
                                        contract, contracts, structures, enums)

        # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type').
        type_name_key = 'type' if 'type' in t['attributes'] else key
        return _find_from_type_name(t['attributes'][type_name_key], contract,
                                    contracts, structures, enums)

    elif t[key] == 'ArrayTypeName':
        length = None
        if is_compact_ast:
            if t['length']:
                length = parse_expression(t['length'], caller_context)
            array_type = parse_type(t['baseType'], contract)
        else:
            if len(t['children']) == 2:
                length = parse_expression(t['children'][1], caller_context)
            else:
                assert len(t['children']) == 1
            array_type = parse_type(t['children'][0], contract)
        return ArrayType(array_type, length)

    elif t[key] == 'Mapping':

        if is_compact_ast:
            mappingFrom = parse_type(t['keyType'], contract)
            mappingTo = parse_type(t['valueType'], contract)
        else:
            assert len(t['children']) == 2

            mappingFrom = parse_type(t['children'][0], contract)
            mappingTo = parse_type(t['children'][1], contract)

        return MappingType(mappingFrom, mappingTo)

    elif t[key] == 'FunctionTypeName':

        if is_compact_ast:
            params = t['parameterTypes']
            return_values = t['returnParameterTypes']
            index = 'parameters'
        else:
            assert len(t['children']) == 2
            params = t['children'][0]
            return_values = t['children'][1]
            index = 'children'

        assert params[key] == 'ParameterList'
        assert return_values[key] == 'ParameterList'

        params_vars = []
        return_values_vars = []
        for p in params[index]:
            var = FunctionTypeVariableSolc(p)
            var.set_offset(p['src'], caller_context.slither)
            var.analyze(caller_context)
            params_vars.append(var)
        for p in return_values[index]:
            var = FunctionTypeVariableSolc(p)

            var.set_offset(p['src'], caller_context.slither)
            var.analyze(caller_context)
            return_values_vars.append(var)

        return FunctionType(params_vars, return_values_vars)

    raise ParsingError('Type name not found ' + str(t))
Ejemplo n.º 2
0
def _find_from_type_name(name, contract, contracts, structures, enums):
    name_elementary = name.split(' ')[0]
    if '[' in name_elementary:
        name_elementary = name_elementary[0:name_elementary.find('[')]
    if name_elementary in ElementaryTypeName:
        depth = name.count('[')
        if depth:
            return ArrayType(ElementaryType(name_elementary),
                             Literal(depth, 'uint256'))
        else:
            return ElementaryType(name_elementary)
    # We first look for contract
    # To avoid collision
    # Ex: a structure with the name of a contract
    name_contract = name
    if name_contract.startswith('contract '):
        name_contract = name_contract[len('contract '):]
    if name_contract.startswith('library '):
        name_contract = name_contract[len('library '):]
    var_type = next((c for c in contracts if c.name == name_contract), None)

    if not var_type:
        var_type = next((st for st in structures if st.name == name), None)
    if not var_type:
        var_type = next((e for e in enums if e.name == name), None)
    if not var_type:
        # any contract can refer to another contract's enum
        enum_name = name
        if enum_name.startswith('enum '):
            enum_name = enum_name[len('enum '):]
        all_enums = [c.enums for c in contracts]
        all_enums = [item for sublist in all_enums for item in sublist]
        var_type = next((e for e in all_enums if e.name == enum_name), None)
        if not var_type:
            var_type = next(
                (e for e in all_enums if e.canonical_name == enum_name), None)
    if not var_type:
        # any contract can refer to another contract's structure
        name_struct = name
        if name_struct.startswith('struct '):
            name_struct = name_struct[len('struct '):]
            name_struct = name_struct.split(' ')[
                0]  # remove stuff like storage pointer at the end
        all_structures = [c.structures for c in contracts]
        all_structures = [
            item for sublist in all_structures for item in sublist
        ]
        var_type = next(
            (st for st in all_structures if st.name == name_struct), None)
        if not var_type:
            var_type = next(
                (st
                 for st in all_structures if st.canonical_name == name_struct),
                None)
        # case where struct xxx.xx[] where not well formed in the AST
        if not var_type:
            depth = 0
            while name_struct.endswith('[]'):
                name_struct = name_struct[0:-2]
                depth += 1
            var_type = next(
                (st
                 for st in all_structures if st.canonical_name == name_struct),
                None)
            if var_type:
                return ArrayType(UserDefinedType(var_type),
                                 Literal(depth, 'uint256'))

    if not var_type:
        var_type = next((f for f in contract.functions if f.name == name),
                        None)
    if not var_type:
        if name.startswith('function '):
            found = re.findall(
                'function \(([ ()a-zA-Z0-9\.,]*)\) returns \(([a-zA-Z0-9\.,]*)\)',
                name)
            assert len(found) == 1
            params = found[0][0].split(',')
            return_values = found[0][1].split(',')
            params = [
                _find_from_type_name(p, contract, contracts, structures, enums)
                for p in params
            ]
            return_values = [
                _find_from_type_name(r, contract, contracts, structures, enums)
                for r in return_values
            ]
            params_vars = []
            return_vars = []
            for p in params:
                var = FunctionTypeVariable()
                var.set_type(p)
                params_vars.append(var)
            for r in return_values:
                var = FunctionTypeVariable()
                var.set_type(r)
                return_vars.append(var)
            return FunctionType(params_vars, return_vars)
    if not var_type:
        if name.startswith('mapping('):
            # nested mapping declared with var
            if name.count('mapping(') == 1:
                found = re.findall(
                    'mapping\(([a-zA-Z0-9\.]*) => ([a-zA-Z0-9\.\[\]]*)\)',
                    name)
            else:
                found = re.findall(
                    'mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)',
                    name)
            assert len(found) == 1
            from_ = found[0][0]
            to_ = found[0][1]

            from_type = _find_from_type_name(from_, contract, contracts,
                                             structures, enums)
            to_type = _find_from_type_name(to_, contract, contracts,
                                           structures, enums)

            return MappingType(from_type, to_type)

    if not var_type:
        raise ParsingError('Type not found ' + str(name))
    return UserDefinedType(var_type)
Ejemplo n.º 3
0
def _find_from_type_name(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements,too-many-arguments
    name: str,
    functions_direct_access: List["Function"],
    contracts_direct_access: List["Contract"],
    structures_direct_access: List["Structure"],
    all_structures: List["Structure"],
    enums_direct_access: List["Enum"],
    all_enums: List["Enum"],
) -> Type:
    name_elementary = name.split(" ")[0]
    if "[" in name_elementary:
        name_elementary = name_elementary[0 : name_elementary.find("[")]
    if name_elementary in ElementaryTypeName:
        depth = name.count("[")
        if depth:
            return ArrayType(ElementaryType(name_elementary), Literal(depth, "uint256"))
        return ElementaryType(name_elementary)
    # We first look for contract
    # To avoid collision
    # Ex: a structure with the name of a contract
    name_contract = name
    if name_contract.startswith("contract "):
        name_contract = name_contract[len("contract ") :]
    if name_contract.startswith("library "):
        name_contract = name_contract[len("library ") :]
    var_type = next((c for c in contracts_direct_access if c.name == name_contract), None)

    if not var_type:
        var_type = next((st for st in structures_direct_access if st.name == name), None)
    if not var_type:
        var_type = next((e for e in enums_direct_access if e.name == name), None)
    if not var_type:
        # any contract can refer to another contract's enum
        enum_name = name
        if enum_name.startswith("enum "):
            enum_name = enum_name[len("enum ") :]
        elif enum_name.startswith("type(enum"):
            enum_name = enum_name[len("type(enum ") : -1]
        # all_enums = [c.enums for c in contracts]
        # all_enums = [item for sublist in all_enums for item in sublist]
        # all_enums += contract.slither.enums_top_level
        var_type = next((e for e in all_enums if e.name == enum_name), None)
        if not var_type:
            var_type = next((e for e in all_enums if e.canonical_name == enum_name), None)
    if not var_type:
        # any contract can refer to another contract's structure
        name_struct = name
        if name_struct.startswith("struct "):
            name_struct = name_struct[len("struct ") :]
            name_struct = name_struct.split(" ")[0]  # remove stuff like storage pointer at the end
        # all_structures = [c.structures for c in contracts]
        # all_structures = [item for sublist in all_structures for item in sublist]
        # all_structures += contract.slither.structures_top_level
        var_type = next((st for st in all_structures if st.name == name_struct), None)
        if not var_type:
            var_type = next((st for st in all_structures if st.canonical_name == name_struct), None)
        # case where struct xxx.xx[] where not well formed in the AST
        if not var_type:
            depth = 0
            while name_struct.endswith("[]"):
                name_struct = name_struct[0:-2]
                depth += 1
            var_type = next((st for st in all_structures if st.canonical_name == name_struct), None)
            if var_type:
                return ArrayType(UserDefinedType(var_type), Literal(depth, "uint256"))

    if not var_type:
        var_type = next((f for f in functions_direct_access if f.name == name), None)
    if not var_type:
        if name.startswith("function "):
            found = re.findall(
                "function \(([ ()\[\]a-zA-Z0-9\.,]*?)\)(?: payable)?(?: (?:external|internal|pure|view))?(?: returns \(([a-zA-Z0-9() \.,]*)\))?",
                name,
            )
            assert len(found) == 1
            params = [v for v in found[0][0].split(",") if v != ""]
            return_values = (
                [v for v in found[0][1].split(",") if v != ""] if len(found[0]) > 1 else []
            )
            params = [
                _find_from_type_name(
                    p,
                    functions_direct_access,
                    contracts_direct_access,
                    structures_direct_access,
                    all_structures,
                    enums_direct_access,
                    all_enums,
                )
                for p in params
            ]
            return_values = [
                _find_from_type_name(
                    r,
                    functions_direct_access,
                    contracts_direct_access,
                    structures_direct_access,
                    all_structures,
                    enums_direct_access,
                    all_enums,
                )
                for r in return_values
            ]
            params_vars = []
            return_vars = []
            for p in params:
                var = FunctionTypeVariable()
                var.set_type(p)
                params_vars.append(var)
            for r in return_values:
                var = FunctionTypeVariable()
                var.set_type(r)
                return_vars.append(var)
            return FunctionType(params_vars, return_vars)
    if not var_type:
        if name.startswith("mapping("):
            # nested mapping declared with var
            if name.count("mapping(") == 1:
                found = re.findall("mapping\(([a-zA-Z0-9\.]*) => ([ a-zA-Z0-9\.\[\]]*)\)", name)
            else:
                found = re.findall(
                    "mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)",
                    name,
                )
            assert len(found) == 1
            from_ = found[0][0]
            to_ = found[0][1]

            from_type = _find_from_type_name(
                from_,
                functions_direct_access,
                contracts_direct_access,
                structures_direct_access,
                all_structures,
                enums_direct_access,
                all_enums,
            )
            to_type = _find_from_type_name(
                to_,
                functions_direct_access,
                contracts_direct_access,
                structures_direct_access,
                all_structures,
                enums_direct_access,
                all_enums,
            )

            return MappingType(from_type, to_type)

    if not var_type:
        raise ParsingError("Type not found " + str(name))
    return UserDefinedType(var_type)
Ejemplo n.º 4
0
def parse_type(t: Union[Dict, UnknownType], caller_context):
    # local import to avoid circular dependency
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements
    # pylint: disable=import-outside-toplevel
    from slither.solc_parsing.expressions.expression_parsing import parse_expression
    from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc
    from slither.solc_parsing.declarations.contract import ContractSolc
    from slither.solc_parsing.declarations.function import FunctionSolc
    from slither.solc_parsing.slitherSolc import SlitherSolc

    # Note: for convenicence top level functions use the same parser than function in contract
    # but contract_parser is set to None
    if isinstance(caller_context, SlitherSolc) or (
        isinstance(caller_context, FunctionSolc) and caller_context.contract_parser is None
    ):
        if isinstance(caller_context, SlitherSolc):
            sl = caller_context.core
            next_context = caller_context
        else:
            assert isinstance(caller_context, FunctionSolc)
            sl = caller_context.underlying_function.slither
            next_context = caller_context.slither_parser
        structures_direct_access = sl.structures_top_level
        all_structuress = [c.structures for c in sl.contracts]
        all_structures = [item for sublist in all_structuress for item in sublist]
        all_structures += structures_direct_access
        enums_direct_access = sl.enums_top_level
        all_enumss = [c.enums for c in sl.contracts]
        all_enums = [item for sublist in all_enumss for item in sublist]
        all_enums += enums_direct_access
        contracts = sl.contracts
        functions = []
    elif isinstance(caller_context, (ContractSolc, FunctionSolc)):
        if isinstance(caller_context, FunctionSolc):
            underlying_func = caller_context.underlying_function
            # If contract_parser is set to None, then underlying_function is a functionContract
            # See note above
            assert isinstance(underlying_func, FunctionContract)
            contract = underlying_func.contract
            next_context = caller_context.contract_parser
        else:
            contract = caller_context.underlying_contract
            next_context = caller_context

        structures_direct_access = contract.structures + contract.slither.structures_top_level
        all_structuress = [c.structures for c in contract.slither.contracts]
        all_structures = [item for sublist in all_structuress for item in sublist]
        all_structures += contract.slither.structures_top_level
        enums_direct_access = contract.enums + contract.slither.enums_top_level
        all_enumss = [c.enums for c in contract.slither.contracts]
        all_enums = [item for sublist in all_enumss for item in sublist]
        all_enums += contract.slither.enums_top_level
        contracts = contract.slither.contracts
        functions = contract.functions + contract.modifiers
    else:
        raise ParsingError(f"Incorrect caller context: {type(caller_context)}")

    is_compact_ast = caller_context.is_compact_ast
    if is_compact_ast:
        key = "nodeType"
    else:
        key = "name"

    if isinstance(t, UnknownType):
        return _find_from_type_name(
            t.name,
            functions,
            contracts,
            structures_direct_access,
            all_structures,
            enums_direct_access,
            all_enums,
        )

    if t[key] == "ElementaryTypeName":
        if is_compact_ast:
            return ElementaryType(t["name"])
        return ElementaryType(t["attributes"][key])

    if t[key] == "UserDefinedTypeName":
        if is_compact_ast:
            return _find_from_type_name(
                t["typeDescriptions"]["typeString"],
                functions,
                contracts,
                structures_direct_access,
                all_structures,
                enums_direct_access,
                all_enums,
            )

        # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type').
        type_name_key = "type" if "type" in t["attributes"] else key
        return _find_from_type_name(
            t["attributes"][type_name_key],
            functions,
            contracts,
            structures_direct_access,
            all_structures,
            enums_direct_access,
            all_enums,
        )

    if t[key] == "ArrayTypeName":
        length = None
        if is_compact_ast:
            if t.get("length", None):
                length = parse_expression(t["length"], caller_context)
            array_type = parse_type(t["baseType"], next_context)
        else:
            if len(t["children"]) == 2:
                length = parse_expression(t["children"][1], caller_context)
            else:
                assert len(t["children"]) == 1
            array_type = parse_type(t["children"][0], next_context)
        return ArrayType(array_type, length)

    if t[key] == "Mapping":

        if is_compact_ast:
            mappingFrom = parse_type(t["keyType"], next_context)
            mappingTo = parse_type(t["valueType"], next_context)
        else:
            assert len(t["children"]) == 2

            mappingFrom = parse_type(t["children"][0], next_context)
            mappingTo = parse_type(t["children"][1], next_context)

        return MappingType(mappingFrom, mappingTo)

    if t[key] == "FunctionTypeName":

        if is_compact_ast:
            params = t["parameterTypes"]
            return_values = t["returnParameterTypes"]
            index = "parameters"
        else:
            assert len(t["children"]) == 2
            params = t["children"][0]
            return_values = t["children"][1]
            index = "children"

        assert params[key] == "ParameterList"
        assert return_values[key] == "ParameterList"

        params_vars: List[FunctionTypeVariable] = []
        return_values_vars: List[FunctionTypeVariable] = []
        for p in params[index]:
            var = FunctionTypeVariable()
            var.set_offset(p["src"], caller_context.slither)

            var_parser = FunctionTypeVariableSolc(var, p)
            var_parser.analyze(caller_context)

            params_vars.append(var)
        for p in return_values[index]:
            var = FunctionTypeVariable()
            var.set_offset(p["src"], caller_context.slither)

            var_parser = FunctionTypeVariableSolc(var, p)
            var_parser.analyze(caller_context)

            return_values_vars.append(var)

        return FunctionType(params_vars, return_values_vars)

    raise ParsingError("Type name not found " + str(t))
Ejemplo n.º 5
0
def parse_type(t: Union[Dict, UnknownType], caller_context):
    # local import to avoid circular dependency
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements
    # pylint: disable=import-outside-toplevel
    from slither.solc_parsing.expressions.expression_parsing import parse_expression
    from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc
    from slither.solc_parsing.declarations.contract import ContractSolc
    from slither.solc_parsing.declarations.function import FunctionSolc

    if isinstance(caller_context, ContractSolc):
        contract = caller_context.underlying_contract
        contract_parser = caller_context
        is_compact_ast = caller_context.is_compact_ast
    elif isinstance(caller_context, FunctionSolc):
        contract = caller_context.underlying_function.contract
        contract_parser = caller_context.contract_parser
        is_compact_ast = caller_context.is_compact_ast
    else:
        raise ParsingError(f"Incorrect caller context: {type(caller_context)}")

    if is_compact_ast:
        key = "nodeType"
    else:
        key = "name"

    structures = contract.structures + contract.slither.top_level_structures
    enums = contract.enums + contract.slither.top_level_enums
    contracts = contract.slither.contracts

    if isinstance(t, UnknownType):
        return _find_from_type_name(t.name, contract, contracts, structures, enums)

    if t[key] == "ElementaryTypeName":
        if is_compact_ast:
            return ElementaryType(t["name"])
        return ElementaryType(t["attributes"][key])

    if t[key] == "UserDefinedTypeName":
        if is_compact_ast:
            return _find_from_type_name(
                t["typeDescriptions"]["typeString"],
                contract,
                contracts,
                structures,
                enums,
            )

        # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type').
        type_name_key = "type" if "type" in t["attributes"] else key
        return _find_from_type_name(
            t["attributes"][type_name_key], contract, contracts, structures, enums
        )

    if t[key] == "ArrayTypeName":
        length = None
        if is_compact_ast:
            if t.get("length", None):
                length = parse_expression(t["length"], caller_context)
            array_type = parse_type(t["baseType"], contract_parser)
        else:
            if len(t["children"]) == 2:
                length = parse_expression(t["children"][1], caller_context)
            else:
                assert len(t["children"]) == 1
            array_type = parse_type(t["children"][0], contract_parser)
        return ArrayType(array_type, length)

    if t[key] == "Mapping":

        if is_compact_ast:
            mappingFrom = parse_type(t["keyType"], contract_parser)
            mappingTo = parse_type(t["valueType"], contract_parser)
        else:
            assert len(t["children"]) == 2

            mappingFrom = parse_type(t["children"][0], contract_parser)
            mappingTo = parse_type(t["children"][1], contract_parser)

        return MappingType(mappingFrom, mappingTo)

    if t[key] == "FunctionTypeName":

        if is_compact_ast:
            params = t["parameterTypes"]
            return_values = t["returnParameterTypes"]
            index = "parameters"
        else:
            assert len(t["children"]) == 2
            params = t["children"][0]
            return_values = t["children"][1]
            index = "children"

        assert params[key] == "ParameterList"
        assert return_values[key] == "ParameterList"

        params_vars: List[FunctionTypeVariable] = []
        return_values_vars: List[FunctionTypeVariable] = []
        for p in params[index]:
            var = FunctionTypeVariable()
            var.set_offset(p["src"], caller_context.slither)

            var_parser = FunctionTypeVariableSolc(var, p)
            var_parser.analyze(caller_context)

            params_vars.append(var)
        for p in return_values[index]:
            var = FunctionTypeVariable()
            var.set_offset(p["src"], caller_context.slither)

            var_parser = FunctionTypeVariableSolc(var, p)
            var_parser.analyze(caller_context)

            return_values_vars.append(var)

        return FunctionType(params_vars, return_values_vars)

    raise ParsingError("Type name not found " + str(t))
def parse_type(
    t: Union[Dict, UnknownType],
    caller_context: Union[CallerContextExpression,
                          "SlitherCompilationUnitSolc"],
) -> Type:
    """
    caller_context can be a SlitherCompilationUnitSolc because we recursively call the function
    and go up in the context's scope. If we are really lost we just go over the SlitherCompilationUnitSolc

    :param t:
    :type t:
    :param caller_context:
    :type caller_context:
    :return:
    :rtype:
    """
    # local import to avoid circular dependency
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements
    # pylint: disable=import-outside-toplevel
    from slither.solc_parsing.expressions.expression_parsing import parse_expression
    from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc
    from slither.solc_parsing.declarations.contract import ContractSolc
    from slither.solc_parsing.declarations.function import FunctionSolc
    from slither.solc_parsing.declarations.custom_error import CustomErrorSolc
    from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc
    from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
    from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc

    sl: "SlitherCompilationUnit"
    renaming: Dict[str, str]
    user_defined_types: Dict[str, TypeAlias]
    # Note: for convenicence top level functions use the same parser than function in contract
    # but contract_parser is set to None
    if isinstance(caller_context, SlitherCompilationUnitSolc) or (
            isinstance(caller_context, FunctionSolc)
            and caller_context.contract_parser is None):
        structures_direct_access: List["Structure"]
        if isinstance(caller_context, SlitherCompilationUnitSolc):
            sl = caller_context.compilation_unit
            next_context = caller_context
            renaming = {}
            user_defined_types = {}
        else:
            assert isinstance(caller_context, FunctionSolc)
            sl = caller_context.underlying_function.compilation_unit
            next_context = caller_context.slither_parser
            renaming = caller_context.underlying_function.file_scope.renaming
            user_defined_types = caller_context.underlying_function.file_scope.user_defined_types
        structures_direct_access = sl.structures_top_level
        all_structuress = [c.structures for c in sl.contracts]
        all_structures = [
            item for sublist in all_structuress for item in sublist
        ]
        all_structures += structures_direct_access
        enums_direct_access = sl.enums_top_level
        all_enumss = [c.enums for c in sl.contracts]
        all_enums = [item for sublist in all_enumss for item in sublist]
        all_enums += enums_direct_access
        contracts = sl.contracts
        functions = []
    elif isinstance(
            caller_context,
        (StructureTopLevelSolc, CustomErrorSolc, TopLevelVariableSolc)):
        if isinstance(caller_context, StructureTopLevelSolc):
            scope = caller_context.underlying_structure.file_scope
        elif isinstance(caller_context, TopLevelVariableSolc):
            scope = caller_context.underlying_variable.file_scope
        else:
            assert isinstance(caller_context, CustomErrorSolc)
            custom_error = caller_context.underlying_custom_error
            if isinstance(custom_error, CustomErrorTopLevel):
                scope = custom_error.file_scope
            else:
                assert isinstance(custom_error, CustomErrorContract)
                scope = custom_error.contract.file_scope

        next_context = caller_context.slither_parser
        structures_direct_access = list(scope.structures.values())
        all_structuress = [c.structures for c in scope.contracts.values()]
        all_structures = [
            item for sublist in all_structuress for item in sublist
        ]
        all_structures += structures_direct_access
        enums_direct_access = []
        all_enums = scope.enums.values()
        contracts = scope.contracts.values()
        functions = list(scope.functions)

        renaming = scope.renaming
        user_defined_types = scope.user_defined_types
    elif isinstance(caller_context, (ContractSolc, FunctionSolc)):
        if isinstance(caller_context, FunctionSolc):
            underlying_func = caller_context.underlying_function
            # If contract_parser is set to None, then underlying_function is a functionContract
            # See note above
            assert isinstance(underlying_func, FunctionContract)
            contract = underlying_func.contract
            next_context = caller_context.contract_parser
            scope = caller_context.underlying_function.file_scope
        else:
            contract = caller_context.underlying_contract
            next_context = caller_context
            scope = caller_context.underlying_contract.file_scope

        structures_direct_access = contract.structures
        structures_direct_access += contract.file_scope.structures.values()
        all_structuress = [
            c.structures for c in contract.file_scope.contracts.values()
        ]
        all_structures = [
            item for sublist in all_structuress for item in sublist
        ]
        all_structures += contract.file_scope.structures.values()
        enums_direct_access: List["Enum"] = contract.enums
        enums_direct_access += contract.file_scope.enums.values()
        all_enumss = [c.enums for c in contract.file_scope.contracts.values()]
        all_enums = [item for sublist in all_enumss for item in sublist]
        all_enums += contract.file_scope.enums.values()
        contracts = contract.file_scope.contracts.values()
        functions = contract.functions + contract.modifiers

        renaming = scope.renaming
        user_defined_types = scope.user_defined_types
    else:
        raise ParsingError(f"Incorrect caller context: {type(caller_context)}")

    is_compact_ast = caller_context.is_compact_ast
    if is_compact_ast:
        key = "nodeType"
    else:
        key = "name"

    if isinstance(t, UnknownType):
        name = t.name
        if name in renaming:
            name = renaming[name]
        if name in user_defined_types:
            return user_defined_types[name]
        return _find_from_type_name(
            name,
            functions,
            contracts,
            structures_direct_access,
            all_structures,
            enums_direct_access,
            all_enums,
        )

    if t[key] == "ElementaryTypeName":
        if is_compact_ast:
            return ElementaryType(t["name"])
        return ElementaryType(t["attributes"][key])

    if t[key] == "UserDefinedTypeName":
        if is_compact_ast:
            name = t["typeDescriptions"]["typeString"]
            if name in renaming:
                name = renaming[name]
            if name in user_defined_types:
                return user_defined_types[name]
            return _find_from_type_name(
                name,
                functions,
                contracts,
                structures_direct_access,
                all_structures,
                enums_direct_access,
                all_enums,
            )

        # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type').
        type_name_key = "type" if "type" in t["attributes"] else key

        name = t["attributes"][type_name_key]
        if name in renaming:
            name = renaming[name]
        if name in user_defined_types:
            return user_defined_types[name]
        return _find_from_type_name(
            name,
            functions,
            contracts,
            structures_direct_access,
            all_structures,
            enums_direct_access,
            all_enums,
        )

    # Introduced with Solidity 0.8
    if t[key] == "IdentifierPath":
        if is_compact_ast:
            name = t["name"]
            if name in renaming:
                name = renaming[name]
            if name in user_defined_types:
                return user_defined_types[name]
            return _find_from_type_name(
                name,
                functions,
                contracts,
                structures_direct_access,
                all_structures,
                enums_direct_access,
                all_enums,
            )

        raise SlitherError("Solidity 0.8 not supported with the legacy AST")

    if t[key] == "ArrayTypeName":
        length = None
        if is_compact_ast:
            if t.get("length", None):
                length = parse_expression(t["length"], caller_context)
            array_type = parse_type(t["baseType"], next_context)
        else:
            if len(t["children"]) == 2:
                length = parse_expression(t["children"][1], caller_context)
            else:
                assert len(t["children"]) == 1
            array_type = parse_type(t["children"][0], next_context)
        return ArrayType(array_type, length)

    if t[key] == "Mapping":

        if is_compact_ast:
            mappingFrom = parse_type(t["keyType"], next_context)
            mappingTo = parse_type(t["valueType"], next_context)
        else:
            assert len(t["children"]) == 2

            mappingFrom = parse_type(t["children"][0], next_context)
            mappingTo = parse_type(t["children"][1], next_context)

        return MappingType(mappingFrom, mappingTo)

    if t[key] == "FunctionTypeName":

        if is_compact_ast:
            params = t["parameterTypes"]
            return_values = t["returnParameterTypes"]
            index = "parameters"
        else:
            assert len(t["children"]) == 2
            params = t["children"][0]
            return_values = t["children"][1]
            index = "children"

        assert params[key] == "ParameterList"
        assert return_values[key] == "ParameterList"

        params_vars: List[FunctionTypeVariable] = []
        return_values_vars: List[FunctionTypeVariable] = []
        for p in params[index]:
            var = FunctionTypeVariable()
            var.set_offset(p["src"], caller_context.compilation_unit)

            var_parser = FunctionTypeVariableSolc(var, p)
            var_parser.analyze(caller_context)

            params_vars.append(var)
        for p in return_values[index]:
            var = FunctionTypeVariable()
            var.set_offset(p["src"], caller_context.compilation_unit)

            var_parser = FunctionTypeVariableSolc(var, p)
            var_parser.analyze(caller_context)

            return_values_vars.append(var)

        return FunctionType(params_vars, return_values_vars)

    raise ParsingError("Type name not found " + str(t))
Ejemplo n.º 7
0
def parse_type(t, caller_context):
    # local import to avoid circular dependency
    from slither.solc_parsing.expressions.expression_parsing import parse_expression
    from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc

    if isinstance(caller_context, Contract):
        contract = caller_context
    elif isinstance(caller_context, Function):
        contract = caller_context.contract
    else:
        logger.error('Incorrect caller context')
        exit(-1)

    structures = contract.structures
    enums = contract.enums
    contracts = contract.slither.contracts

    if isinstance(t, UnknownType):
        return _find_from_type_name(t.name, contract, contracts, structures,
                                    enums)

    elif t['name'] == 'ElementaryTypeName':
        return ElementaryType(t['attributes']['name'])

    elif t['name'] == 'UserDefinedTypeName':
        return _find_from_type_name(t['attributes']['name'], contract,
                                    contracts, structures, enums)

    elif t['name'] == 'ArrayTypeName':
        length = None
        if len(t['children']) == 2:
            length = parse_expression(t['children'][1], caller_context)
        else:
            assert len(t['children']) == 1
        array_type = parse_type(t['children'][0], contract)
        return ArrayType(array_type, length)

    elif t['name'] == 'Mapping':

        assert len(t['children']) == 2

        mappingFrom = parse_type(t['children'][0], contract)
        mappingTo = parse_type(t['children'][1], contract)

        return MappingType(mappingFrom, mappingTo)

    elif t['name'] == 'FunctionTypeName':
        assert len(t['children']) == 2

        params = t['children'][0]
        return_values = t['children'][1]

        assert params['name'] == 'ParameterList'
        assert return_values['name'] == 'ParameterList'

        params_vars = []
        return_values_vars = []
        for p in params['children']:
            var = FunctionTypeVariableSolc(p)
            var.set_offset(p['src'], caller_context.slither)
            var.analyze(caller_context)
            params_vars.append(var)
        for p in return_values['children']:
            var = FunctionTypeVariableSolc(p)

            var.set_offset(p['src'], caller_context.slither)
            var.analyze(caller_context)
            return_values_vars.append(var)

        return FunctionType(params_vars, return_values_vars)

    logger.error('Type name not found ' + str(t))
    exit(-1)