示例#1
0
 def call(self, node, _, args, alias_map=None):
   node, var = self.ctx.attribute_handler.get_attribute(
       node, self, "__call__", self.to_binding(node))
   if var is not None and var.bindings:
     return function.call_function(self.ctx, node, var, args)
   else:
     raise function.NotCallable(self)
示例#2
0
 def _lookup_from_mro_and_handle_descriptors(self, node, cls, name, valself,
                                             skip):
     attr = self._lookup_from_mro(node, cls, name, valself, skip)
     if not attr.bindings:
         return node, None
     if isinstance(cls, abstract.InterpreterClass):
         result = self.ctx.program.NewVariable()
         nodes = []
         # Deal with descriptors as a potential additional level of indirection.
         for v in attr.bindings:
             value = v.data
             if (isinstance(value, special_builtins.PropertyInstance)
                     and valself and valself.data == cls):
                 node2, getter = node, None
             else:
                 node2, getter = self.get_attribute(node, value, "__get__",
                                                    v)
             if getter is not None:
                 posargs = []
                 if valself and valself.data != cls:
                     posargs.append(valself.AssignToNewVariable())
                 else:
                     posargs.append(self.ctx.convert.none.to_variable(node))
                 posargs.append(cls.to_variable(node))
                 node2, get_result = function.call_function(
                     self.ctx, node2, getter, function.Args(tuple(posargs)))
                 for getter in get_result.bindings:
                     result.AddBinding(getter.data, [getter], node2)
             else:
                 result.AddBinding(value, [v], node2)
             nodes.append(node2)
         if nodes:
             return self.ctx.join_cfg_nodes(nodes), result
     return node, attr
示例#3
0
 def call_pytd(self, node, name, *args):
   """Call the (original) pytd version of a method we overwrote."""
   return function.call_function(
       self.ctx,
       node,
       self._super[name],
       function.Args(args),
       fallback_to_unsolvable=False)
示例#4
0
 def _call_method(self, node, value, method_name, args):
     node, method = self.ctx.attribute_handler.get_attribute(
         node, value.data, method_name, value)
     if method:
         call_repr = "%s.%s(..._)" % (self.name, method_name)
         log.debug("calling %s", call_repr)
         node, ret = function.call_function(self.ctx, node, method, args)
         log.debug("%s returned %r", call_repr, ret)
     return node
示例#5
0
 def call(self, node, _, args):
     self.match_args(node, args)
     arg = args.posargs[0]
     node, fn = self.get_underlying_method(node, arg, "__abs__")
     if fn is not None:
         return function.call_function(self.ctx, node, fn, function.Args(
             ()))
     else:
         return node, self.ctx.new_unsolvable(node)
示例#6
0
 def call(self, node, _, args):
     self.match_args(node, args)
     arg, default = self._get_args(args)
     node, fn = self.get_underlying_method(node, arg, "__next__")
     if fn is not None:
         node, ret = function.call_function(self.ctx, node, fn,
                                            function.Args(()))
         ret.PasteVariable(default)
         return node, ret
     else:
         return node, self.ctx.new_unsolvable(node)
示例#7
0
 def _call_new_and_init(self, node, value, args):
     """Call __new__ if it has been overridden on the given value."""
     node, new = self.get_own_new(node, value)
     if new is None:
         return node, None
     cls = value.AssignToNewVariable(node)
     new_args = args.replace(posargs=(cls, ) + args.posargs)
     node, variable = function.call_function(self.ctx, node, new, new_args)
     for val in variable.bindings:
         # If val.data is a class, call_init mistakenly calls val.data's __init__
         # method rather than that of val.data.cls.
         if not isinstance(val.data, Class) and self == val.data.cls:
             node = self.call_init(node, val, args)
     return node, variable
示例#8
0
def _call_binop_on_bindings(node, name, xval, yval, ctx):
  """Call a binary operator on two cfg.Binding objects."""
  rname = slots.REVERSE_NAME_MAPPING.get(name)
  if rname and isinstance(xval.data, abstract.AMBIGUOUS_OR_EMPTY):
    # If the reverse operator is possible and x is ambiguous, then we have no
    # way of determining whether __{op} or __r{op}__ is called.  Technically,
    # the result is also unknown if y is ambiguous, but it is almost always
    # reasonable to assume that, e.g., "hello " + y is a string, even though
    # y could define __radd__.
    return node, ctx.program.NewVariable(
        [ctx.convert.unsolvable], [xval, yval], node)
  options = [(xval, yval, name)]
  if rname:
    options.append((yval, xval, rname))
    if _overrides(yval.data.cls, xval.data.cls, rname):
      # If y is a subclass of x and defines its own reverse operator, then we
      # need to try y.__r{op}__ before x.__{op}__.
      options.reverse()
  error = None
  for left_val, right_val, attr_name in options:
    if (isinstance(left_val.data, abstract.Class) and
        attr_name == "__getitem__"):
      # We're parameterizing a type annotation. Set valself to None to
      # differentiate this action from a real __getitem__ call on the class.
      valself = None
    else:
      valself = left_val
    node, attr_var = ctx.attribute_handler.get_attribute(
        node, left_val.data, attr_name, valself)
    if attr_var and attr_var.bindings:
      args = function.Args(posargs=(right_val.AssignToNewVariable(),))
      try:
        return function.call_function(
            ctx, node, attr_var, args, fallback_to_unsolvable=False)
      except (function.DictKeyMissing, function.FailedFunctionCall) as e:
        # It's possible that this call failed because the function returned
        # NotImplemented.  See, e.g.,
        # test_operators.ReverseTest.check_reverse(), in which 1 {op} Bar() ends
        # up using Bar.__r{op}__. Thus, we need to save the error and try the
        # other operator.
        if e > error:
          error = e
  if error:
    raise error  # pylint: disable=raising-bad-type
  else:
    return node, None
示例#9
0
 def _get_attribute_computed(self, node, cls, name, valself,
                             compute_function):
     """Call compute_function (if defined) to compute an attribute."""
     assert isinstance(cls,
                       (abstract.Class, abstract.AMBIGUOUS_OR_EMPTY)), cls
     if (valself and not isinstance(valself.data, abstract.Module)
             and self._computable(name)):
         attr_var = self._lookup_from_mro(
             node,
             cls,
             compute_function,
             valself,
             skip={self.ctx.convert.object_type})
         if attr_var and attr_var.bindings:
             name_var = self.ctx.convert.constant_to_var(name, node=node)
             return function.call_function(self.ctx, node, attr_var,
                                           function.Args((name_var, )))
     return node, None
示例#10
0
 def call_metaclass_init(self, node):
     """Call the metaclass's __init__ method if it does anything interesting."""
     if self.cls.full_name == "builtins.type":
         return node
     node, init = self.ctx.attribute_handler.get_attribute(
         node, self.cls, "__init__")
     if not init or not any(
             _isinstance(f, "SignedFunction") for f in init.data):
         # Only SignedFunctions (InterpreterFunction and SimpleFunction) have
         # interesting side effects.
         return node
     args = function.Args(
         posargs=(self.to_variable(node),
                  self.ctx.convert.build_string(node, self.name),
                  self.ctx.convert.build_tuple(node, self.bases()),
                  self.ctx.new_unsolvable(node)))
     log.debug("Calling __init__ on metaclass %s of class %s",
               self.cls.name, self.name)
     node, _ = function.call_function(self.ctx, node, init, args)
     return node
示例#11
0
    def call_with_fake_args(self, node0, funcv):
        """Attempt to call the given function with made-up arguments."""
        # Note that this should only be used for functions that raised a
        # FailedFunctionCall error. This is not guaranteed to successfully call a
        # function that raised DictKeyMissing instead.
        nodes = []
        rets = []
        for funcb in funcv.bindings:
            func = funcb.data
            log.info("Trying %s with fake arguments", func)

            if isinstance(func, abstract.INTERPRETER_FUNCTION_TYPES):
                node1, args = self.create_method_arguments(node0, func)
                # Once the args are generated, try calling the function.
                # call_function will check fallback_to_unsolvable if a DictKeyMissing or
                # FailedFunctionCall error is raised when the target function is called.
                # DictKeyMissing doesn't trigger call_with_fake_args, so that shouldn't
                # be raised again, and generating fake arguments should avoid any
                # FailedFunctionCall errors. To prevent an infinite recursion loop, set
                # fallback_to_unsolvable to False just in case.
                # This means any additional errors that may be raised will be passed to
                # the call_function that called this method in the first place.
                node2, ret = function.call_function(
                    self.ctx,
                    node1,
                    funcb.AssignToNewVariable(),
                    args,
                    fallback_to_unsolvable=False)
                nodes.append(node2)
                rets.append(ret)

        if nodes:
            ret = self.ctx.join_variables(node0, rets)
            node = self.ctx.join_cfg_nodes(nodes)
            if ret.bindings:
                return node, ret
        else:
            node = node0
        log.info("Unable to generate fake arguments for %s", funcv)
        return node, self.ctx.new_unsolvable(node)
示例#12
0
 def call(self, node, func, args, alias_map=None):
     var = self.ctx.program.NewVariable(self.options, [], node)
     return function.call_function(self.ctx, node, var, args)
示例#13
0
 def call(self, node, func, args, alias_map=None):
     var = self.instance.get_instance_type_parameter(self.name)
     if var.bindings:
         return function.call_function(self.ctx, node, var, args)
     else:
         return node, self.ctx.convert.empty.to_variable(self.ctx.root_node)
示例#14
0
 def fdelete_slot(self, node, obj):
     return function.call_function(self.ctx, node, self.fdel,
                                   function.Args((obj, )))
示例#15
0
 def fset_slot(self, node, obj, value):
     return function.call_function(self.ctx, node, self.fset,
                                   function.Args((obj, value)))
示例#16
0
 def fget_slot(self, node, obj, objtype):
     return function.call_function(self.ctx, node, self.fget,
                                   function.Args((obj, )))