Detects and obtains functions which are shadowed immediately by the provided ancestor contract.
    :param contract: The ancestor contract which we check for function shadowing within.
    :return: A list of tuples (overshadowing_function, overshadowed_immediate_base_contract, overshadowed_function)
    -overshadowing_function is the function defined within the provided contract that overshadows another
    definition.
    -overshadowed_immediate_base_contract is the immediate inherited-from contract that provided the shadowed
    function (could have provided it through inheritance, does not need to directly define it).
    -overshadowed_function is the function definition which is overshadowed by the provided contract's definition.

def detect_direct_function_shadowing(contract):
    """
    Detects and obtains functions which are shadowed immediately by the provided ancestor contract.
    :param contract: The ancestor contract which we check for function shadowing within.
    :return: A list of tuples (overshadowing_function, overshadowed_immediate_base_contract, overshadowed_function)
    -overshadowing_function is the function defined within the provided contract that overshadows another
    definition.
    -overshadowed_immediate_base_contract is the immediate inherited-from contract that provided the shadowed
    function (could have provided it through inheritance, does not need to directly define it).
    -overshadowed_function is the function definition which is overshadowed by the provided contract's definition.
    """
    functions_declared = {function.full_name: function for function in contract.functions_and_modifiers_not_inherited}
    results = {}
    for base_contract in reversed(contract.immediate_inheritance):
        for base_function in base_contract.functions_and_modifiers:

            # We already found the most immediate shadowed definition for this function, skip to the next.
            if base_function.full_name in results:
                continue

            # If this function is implemented and it collides with a definition in our immediate contract, we add
            # it to our results.
            if base_function.is_implemented and base_function.full_name in functions_declared:
                results[base_function.full_name] = (functions_declared[base_function.full_name], base_contract, base_function)

    return list(results.values())