Example #1
0
 def call(self, node, funcv, args):
     if len(args.posargs) != 1:
         raise function.WrongArgCount(self._SIGNATURE, args, self.ctx)
     arg = args.posargs[0]
     for d in arg.data:
         d.is_classmethod = True
         d.is_attribute_of_class = True
     return node, ClassMethodInstance(self.ctx, self, arg).to_variable(node)
Example #2
0
 def call(self, node, _, args):
     result = self.ctx.program.NewVariable()
     num_args = len(args.posargs)
     if num_args == 0:
         # The implicit type argument is available in a freevar named '__class__'.
         cls_var = None
         # If we are in a list comprehension we want the enclosing frame.
         index = -1
         while self.ctx.vm.frames[index].f_code.co_name == "<listcomp>":
             index -= 1
         frame = self.ctx.vm.frames[index]
         for i, free_var in enumerate(frame.f_code.co_freevars):
             if free_var == abstract.BuildClass.CLOSURE_NAME:
                 cls_var = frame.cells[len(frame.f_code.co_cellvars) + i]
                 break
         if not (cls_var and cls_var.bindings):
             self.ctx.errorlog.invalid_super_call(
                 self.ctx.vm.frames,
                 message="Missing __class__ closure for super call.",
                 details=
                 "Is 'super' being called from a method defined in a class?"
             )
             return node, self.ctx.new_unsolvable(node)
         # The implicit super object argument is the first argument to the function
         # calling 'super'.
         self_arg = frame.first_arg
         if not self_arg:
             self.ctx.errorlog.invalid_super_call(
                 self.ctx.vm.frames,
                 message="Missing 'self' argument to 'super' call.")
             return node, self.ctx.new_unsolvable(node)
         super_objects = self_arg.bindings
     elif 1 <= num_args <= 2:
         cls_var = args.posargs[0]
         super_objects = args.posargs[1].bindings if num_args == 2 else [
             None
         ]
     else:
         raise function.WrongArgCount(self._SIGNATURE, args, self.ctx)
     for cls in cls_var.bindings:
         if not isinstance(cls.data,
                           (abstract.Class, abstract.AMBIGUOUS_OR_EMPTY)):
             bad = function.BadParam(name="cls",
                                     expected=self.ctx.convert.type_type)
             raise function.WrongArgTypes(self._SIGNATURE,
                                          args,
                                          self.ctx,
                                          bad_param=bad)
         for obj in super_objects:
             if obj:
                 result.AddBinding(
                     SuperInstance(cls.data, obj.data, self.ctx),
                     [cls, obj], node)
             else:
                 result.AddBinding(SuperInstance(cls.data, None, self.ctx),
                                   [cls], node)
     return node, result
Example #3
0
 def call(self, node, _, args):
     if len(args.posargs) == 1:
         a, = args.posargs
         t = None
     elif len(args.posargs) == 2:
         a, t = args.posargs
     else:
         raise function.WrongArgCount(self._SIGNATURE, args, self.ctx)
     self.ctx.errorlog.assert_type(self.ctx.vm.frames, node, a, t)
     return node, self.ctx.convert.build_none(node)
Example #4
0
 def call(self, node, _, args, alias_map=None):
     sig = None
     if isinstance(self.func.__self__, _classes.CallableClass):
         sig = function.Signature.from_callable(self.func.__self__)
     args = args.simplify(node, self.ctx, match_signature=sig)
     posargs = [u.AssignToNewVariable(node) for u in args.posargs]
     namedargs = {
         k: u.AssignToNewVariable(node)
         for k, u in args.namedargs.items()
     }
     try:
         inspect.signature(self.func).bind(node, *posargs, **namedargs)
     except ValueError as e:
         # Happens for, e.g.,
         #   def f((x, y)): pass
         #   f((42,))
         raise NotImplementedError(
             "Wrong number of values to unpack") from e
     except TypeError as e:
         # The possible errors here are:
         #   (1) wrong arg count
         #   (2) duplicate keyword
         #   (3) unexpected keyword
         # The way we constructed namedargs rules out (2).
         if "keyword" in utils.message(e):
             # Happens for, e.g.,
             #   def f(*args): pass
             #   f(x=42)
             raise NotImplementedError("Unexpected keyword") from e
         # The function was passed the wrong number of arguments. The signature is
         # ([self, ]node, ...). The length of "..." tells us how many variables
         # are expected.
         expected_argcount = len(inspect.getfullargspec(self.func).args) - 1
         if inspect.ismethod(self.func) and self.func.__self__ is not None:
             expected_argcount -= 1
         actual_argcount = len(posargs) + len(namedargs)
         if (actual_argcount > expected_argcount
                 or (not args.starargs and not args.starstarargs)):
             # If we have too many arguments, or starargs and starstarargs are both
             # empty, then we can be certain of a WrongArgCount error.
             argnames = tuple("_" + str(i)
                              for i in range(expected_argcount))
             sig = function.Signature(self.name, argnames, 0, None, set(),
                                      None, {}, {}, {})
             raise function.WrongArgCount(sig, args, self.ctx)
         assert actual_argcount < expected_argcount
         # Assume that starargs or starstarargs fills in the missing arguments.
         # Instead of guessing where these arguments should go, overwrite all of
         # the arguments with a list of unsolvables of the correct length, which
         # is guaranteed to give us a correct (but imprecise) analysis.
         posargs = [
             self.ctx.new_unsolvable(node) for _ in range(expected_argcount)
         ]
         namedargs = {}
     return self.func(node, *posargs, **namedargs)
Example #5
0
 def call(self, node, unused, args):
   if len(args.posargs) != 1:
     sig = function.Signature.from_param_names(
         "%s.add_metaclass" % self.module_name, ("cls",))
     raise function.WrongArgCount(sig, args, self.ctx)
   cls_var = args.posargs[0]
   for b in cls_var.bindings:
     cls = b.data
     log.debug("Adding metaclass %r to class %r", self.meta, cls)
     cls.cls = self.meta
     # For metaclasses defined natively or using with_metaclass, the
     # metaclass's initializer is called in vm.make_class. However, with
     # add_metaclass, the metaclass is not known until the decorator fires.
     if isinstance(cls, abstract.Class):
       node = cls.call_metaclass_init(node)
   return node, cls_var
Example #6
0
 def call_slot(self, node, *args, **kwargs):
     """Implementation of CallableClass.__call__."""
     if kwargs:
         raise function.WrongKeywordArgs(
             function.Signature.from_callable(self),
             function.Args(posargs=args, namedargs=kwargs), self.ctx,
             kwargs.keys())
     if len(args) != self.num_args:
         raise function.WrongArgCount(
             function.Signature.from_callable(self),
             function.Args(posargs=args), self.ctx)
     formal_args = [(function.argname(i), self.formal_type_parameters[i])
                    for i in range(self.num_args)]
     substs = [datatypes.AliasingDict()]
     bad_param = None
     for view in abstract_utils.get_views(args, node):
         arg_dict = {
             function.argname(i): view[args[i]]
             for i in range(self.num_args)
         }
         subst, bad_param = self.ctx.matcher(node).compute_subst(
             formal_args, arg_dict, view, None)
         if subst is not None:
             substs = [subst]
             break
     else:
         if bad_param:
             raise function.WrongArgTypes(
                 function.Signature.from_callable(self),
                 function.Args(posargs=args),
                 self.ctx,
                 bad_param=bad_param)
     ret = self.ctx.annotation_utils.sub_one_annotation(
         node, self.formal_type_parameters[abstract_utils.RET], substs)
     node, retvar = self.ctx.vm.init_class(node, ret)
     return node, retvar
Example #7
0
  def _map_args(self, args, view):
    """Map the passed arguments to a name->binding dictionary.

    Args:
      args: The passed arguments.
      view: A variable->binding dictionary.

    Returns:
      A tuple of:
        a list of formal arguments, each a (name, abstract value) pair;
        a name->binding dictionary of the passed arguments.

    Raises:
      InvalidParameters: If the passed arguments don't match this signature.
    """
    formal_args = [(p.name, self.signature.annotations[p.name])
                   for p in self.pytd_sig.params]
    arg_dict = {}

    # positional args
    for name, arg in zip(self.signature.param_names, args.posargs):
      arg_dict[name] = view[arg]
    num_expected_posargs = len(self.signature.param_names)
    if len(args.posargs) > num_expected_posargs and not self.pytd_sig.starargs:
      raise function.WrongArgCount(self.signature, args, self.ctx)
    # Extra positional args are passed via the *args argument.
    varargs_type = self.signature.annotations.get(self.signature.varargs_name)
    if isinstance(varargs_type, _classes.ParameterizedClass):
      for (i, vararg) in enumerate(args.posargs[num_expected_posargs:]):
        name = function.argname(num_expected_posargs + i)
        arg_dict[name] = view[vararg]
        formal_args.append(
            (name, varargs_type.get_formal_type_parameter(abstract_utils.T)))

    # named args
    for name, arg in args.namedargs.items():
      if name in arg_dict:
        raise function.DuplicateKeyword(self.signature, args, self.ctx, name)
      arg_dict[name] = view[arg]
    kws = set(args.namedargs)
    extra_kwargs = kws - {p.name for p in self.pytd_sig.params}
    if extra_kwargs and not self.pytd_sig.starstarargs:
      raise function.WrongKeywordArgs(
          self.signature, args, self.ctx, extra_kwargs)
    posonly_kwargs = kws.intersection(self.signature.posonly_params)
    if posonly_kwargs:
      raise function.WrongKeywordArgs(
          self.signature, args, self.ctx, posonly_kwargs)
    # Extra keyword args are passed via the **kwargs argument.
    kwargs_type = self.signature.annotations.get(self.signature.kwargs_name)
    if isinstance(kwargs_type, _classes.ParameterizedClass):
      # We sort the kwargs so that matching always happens in the same order.
      for name in sorted(extra_kwargs):
        formal_args.append(
            (name, kwargs_type.get_formal_type_parameter(abstract_utils.V)))

    # packed args
    packed_args = [("starargs", self.signature.varargs_name),
                   ("starstarargs", self.signature.kwargs_name)]
    for arg_type, name in packed_args:
      actual = getattr(args, arg_type)
      pytd_val = getattr(self.pytd_sig, arg_type)
      if actual and pytd_val:
        arg_dict[name] = view[actual]
        # The annotation is Tuple or Dict, but the passed arg only has to be
        # Iterable or Mapping.
        typ = self.ctx.convert.widen_type(self.signature.annotations[name])
        formal_args.append((name, typ))

    return formal_args, arg_dict
    def _map_args(self, node, args):
        """Map call args to function args.

    This emulates how Python would map arguments of function calls. It takes
    care of keyword parameters, default parameters, and *args and **kwargs.

    Args:
      node: The current CFG node.
      args: The arguments.

    Returns:
      A dictionary, mapping strings (parameter names) to cfg.Variable.

    Raises:
      function.FailedFunctionCall: If the caller supplied incorrect arguments.
    """
        # Originate a new variable for each argument and call.
        posargs = [u.AssignToNewVariable(node) for u in args.posargs]
        kws = {
            k: u.AssignToNewVariable(node)
            for k, u in args.namedargs.items()
        }
        sig = self.signature
        callargs = {
            name: self.ctx.program.NewVariable(default.data, [], node)
            for name, default in sig.defaults.items()
        }
        positional = dict(zip(sig.param_names, posargs))
        for key in positional:
            if key in kws:
                raise function.DuplicateKeyword(sig, args, self.ctx, key)
        kwnames = set(kws)
        extra_kws = kwnames.difference(sig.param_names + sig.kwonly_params)
        if extra_kws and not sig.kwargs_name:
            raise function.WrongKeywordArgs(sig, args, self.ctx, extra_kws)
        posonly_kws = kwnames.intersection(sig.posonly_params)
        if posonly_kws:
            raise function.WrongKeywordArgs(sig, args, self.ctx, posonly_kws)
        callargs.update(positional)
        callargs.update(kws)
        for key, kwonly in self.get_nondefault_params():
            if key not in callargs:
                if args.starstarargs or (args.starargs and not kwonly):
                    # We assume that because we have *args or **kwargs, we can use these
                    # to fill in any parameters we might be missing.
                    callargs[key] = self.ctx.new_unsolvable(node)
                else:
                    raise function.MissingParameter(sig, args, self.ctx, key)
        for key in sig.kwonly_params:
            if key not in callargs:
                raise function.MissingParameter(sig, args, self.ctx, key)
        if sig.varargs_name:
            varargs_name = sig.varargs_name
            extraneous = posargs[self.argcount(node):]
            if args.starargs:
                if extraneous:
                    log.warning("Not adding extra params to *%s", varargs_name)
                callargs[varargs_name] = args.starargs.AssignToNewVariable(
                    node)
            else:
                callargs[varargs_name] = self.ctx.convert.build_tuple(
                    node, extraneous)
        elif len(posargs) > self.argcount(node):
            raise function.WrongArgCount(sig, args, self.ctx)
        if sig.kwargs_name:
            kwargs_name = sig.kwargs_name
            # Build a **kwargs dictionary out of the extraneous parameters
            if args.starstarargs:
                callargs[kwargs_name] = args.starstarargs.AssignToNewVariable(
                    node)
            else:
                omit = sig.param_names + sig.kwonly_params
                k = _instances.Dict(self.ctx)
                k.update(node, args.namedargs, omit=omit)
                callargs[kwargs_name] = k.to_variable(node)
        return callargs
Example #9
0
 def call(self, node, funcv, args):
     if len(args.posargs) != 1:
         raise function.WrongArgCount(self._SIGNATURE, args, self.ctx)
     arg = args.posargs[0]
     return node, StaticMethodInstance(self.ctx, self,
                                       arg).to_variable(node)