Resulting node alias to the return_alias of called function,
        if the function is already known by Pythran (i.e. it's an Intrinsic)
        or if Pythran already computed it's ``return_alias`` behavior.

        >>> from pythran import passmanager
        >>> pm = passmanager.PassManager('demo')
        >>> fun = """
        ... def f(a): return a
        ... def foo(b): c = f(b)"""
        >>> module = ast.parse(fun)

        The ``f`` function create aliasing between
        the returned value and its first argument.

        >>> result = pm.gather(Aliases, module)
        >>> Aliases.dump(result, filter=ast.Call)
        f(b) => ['b']

        This also works with intrinsics, e.g ``dict.setdefault`` which
        may create alias between its third argument and the return value.

        >>> fun = 'def foo(a, d): __builtin__.dict.setdefault(d, 0, a)'
        >>> module = ast.parse(fun)
        >>> result = pm.gather(Aliases, module)
        >>> Aliases.dump(result, filter=ast.Call)
        __builtin__.dict.setdefault(d, 0, a) => ['<unbound-value>', 'a']

        Note that complex cases can arise, when one of the formal parameter
        is already known to alias to various values:

        >>> fun = """
        ... def f(a, b): return a and b
        ... def foo(A, B, C, D): return f(A or B, C or D)"""
        >>> module = ast.parse(fun)
        >>> result = pm.gather(Aliases, module)
        >>> Aliases.dump(result, filter=ast.Call)
        f((A or B), (C or D)) => ['A', 'B', 'C', 'D']

def visit_Call(self, node):
        '''
        Resulting node alias to the return_alias of called function,
        if the function is already known by Pythran (i.e. it's an Intrinsic)
        or if Pythran already computed it's ``return_alias`` behavior.

        >>> from pythran import passmanager
        >>> pm = passmanager.PassManager('demo')
        >>> fun = """
        ... def f(a): return a
        ... def foo(b): c = f(b)"""
        >>> module = ast.parse(fun)

        The ``f`` function create aliasing between
        the returned value and its first argument.

        >>> result = pm.gather(Aliases, module)
        >>> Aliases.dump(result, filter=ast.Call)
        f(b) => ['b']

        This also works with intrinsics, e.g ``dict.setdefault`` which
        may create alias between its third argument and the return value.

        >>> fun = 'def foo(a, d): __builtin__.dict.setdefault(d, 0, a)'
        >>> module = ast.parse(fun)
        >>> result = pm.gather(Aliases, module)
        >>> Aliases.dump(result, filter=ast.Call)
        __builtin__.dict.setdefault(d, 0, a) => ['<unbound-value>', 'a']

        Note that complex cases can arise, when one of the formal parameter
        is already known to alias to various values:

        >>> fun = """
        ... def f(a, b): return a and b
        ... def foo(A, B, C, D): return f(A or B, C or D)"""
        >>> module = ast.parse(fun)
        >>> result = pm.gather(Aliases, module)
        >>> Aliases.dump(result, filter=ast.Call)
        f((A or B), (C or D)) => ['A', 'B', 'C', 'D']
        '''
        self.generic_visit(node)
        f = node.func
        # special handler for bind functions
        if isinstance(f, ast.Attribute) and f.attr == "partial":
            return self.add(node, {node})
        else:
            return_alias = self.call_return_alias(node)
            # expand collected aliases
            all_aliases = set()
            for value in return_alias:
                # no translation
                if isinstance(value, (ContainerOf, ast.FunctionDef,
                                      Intrinsic)):
                    all_aliases.add(value)
                elif value in self.result:
                    all_aliases.update(self.result[value])
                else:
                    try:
                        ap = Aliases.access_path(value)
                        all_aliases.update(self.aliases.get(ap, ()))
                    except NotImplementedError:
                        # should we do something better here?
                        all_aliases.add(value)
            return self.add(node, all_aliases)