Ejemplo n.º 1
0
def _infer_end_subscript(node: nodes.Subscript, context=None):
    default = None
    if not isinstance(node.slice, nodes.Index) and not isinstance(
            node.slice.value, nodes.Const):
        raise inference.UseInferenceDefault
    t = get_prm_type(node.slice.value.value)
    if t is None:
        raise inference.UseInferenceDefault

    proxy = Z3Proxy(MANAGER.make_z3_var(node.slice.value.value, t), default)
    if t is bool and context.conditions_mode != context_mod.ConditionsMode.IN_PROGRESS:
        # yield all combinations of the bool, only in non-conditions expanding mode
        ast_true = nodes.Const(True)
        true_branch = inference.InferenceResult.load_result(
            ast_true,
            bound_conditions={proxy},
            selected_operand={hash((node.slice.value.value, t)): ast_true})
        yield true_branch
        ast_false = nodes.Const(False)
        false_branch = inference.InferenceResult.load_result(
            ast_false,
            bound_conditions={proxy.invert_condition()},
            selected_operand={hash((node.slice.value.value, t)): ast_false},
        )
        yield false_branch

    else:
        yield inference.InferenceResult(proxy, status=True)
 def test_link_1_var(self):
     # x = 2
     parent = nodes.LocalsDictNode()
     ast_source_node = nodes.Assign(parent=parent)
     ast_source_node.postinit(targets=[
         nodes.AssignName.quick_build(id="x",
                                      version=0,
                                      parent=ast_source_node)
     ],
                              value=nodes.Const(2))
     parent.locals = {"x_0": ast_source_node}
     # y = x
     ast_target_node = nodes.Assign(parent=parent)
     ast_target_node.postinit(
         targets=[
             nodes.AssignName.quick_build(id="y",
                                          version=0,
                                          parent=ast_target_node)
         ],
         value=nodes.Name.quick_build(id="x",
                                      version=0,
                                      parent=ast_target_node),
     )
     link_stmts_to_def(ast_target_node)
     assert ast_target_node.value.links == ast_source_node
Ejemplo n.º 3
0
 def _infer(self, context=None, inferred_attr=None):
     if context and context.model is not None:
         try:
             z3_result = context.model.eval(self.value)
             defaults = []
             for arg in z3.z3util.get_vars(z3_result):
                 if arg in self.defaults:
                     defaults.append(
                         (arg, utilities.make_z3_const(self.defaults[arg])))
                 else:
                     MANAGER.logger.info(
                         "Z3",
                         "Arg: {} from expr: {} is missing a default value",
                         arg, z3_result)
             if defaults:
                 z3_result = z3.substitute(z3_result, defaults)
             z3_result = context.model.eval(z3_result,
                                            model_completion=True)
             py_val = utilities.get_py_val_from_z3_val(z3_result)
             if type(py_val) is not bool:
                 # don't add it in model used since bool value can't be change at later stage
                 context.z3_model_used[self.value] = z3_result
             yield inference.InferenceResult.load_result(
                 nodes.Const(py_val))
         except NotImplementedError:
             yield inference.InferenceResult.load_result(self,
                                                         substituted=True)
     else:
         yield inference.InferenceResult.load_result(self, substituted=True)
Ejemplo n.º 4
0
def _infer_ceil_division(node: nodes.Call, context):
    """
    Ceiling division will be implemented by using (x + y - 1) / y
    taken from: https://stackoverflow.com/a/2745086/9677833
    """
    left = node.args[0].args[0].left.args[0]
    right = node.args[0].args[0].right
    x_p_y = nodes.BinOp()
    x_p_y.postinit(left, "+", right)
    x_p_y_min_1 = nodes.BinOp()
    x_p_y.parent = x_p_y_min_1
    x_p_y_min_1.postinit(x_p_y, "-", nodes.Const(1))
    x_p_y_min_1_div_y = nodes.BinOp()
    x_p_y_min_1.parent = x_p_y_min_1_div_y
    x_p_y_min_1_div_y.postinit(x_p_y_min_1, "/", right)
    MANAGER.apply_transform(x_p_y_min_1_div_y)
    yield from x_p_y_min_1_div_y.infer(context)
Ejemplo n.º 5
0
 def infer_binop(node, context=None):
     # custom bin op inference here
     yield InferenceResult.load_result(nodes.Const(4))
def _infer_round(node, context=None):
    """
    Interesting note in python 2 round function:
    round() will always return float. The way python 2 handles
    it is first called float(), which will triggers __float__,
    then perform rounding *without* delegating to __round__.
    __round__ is only available in python 3.

    The approach is here in dealing with type inference for
    python 2 is to just yield float type without getting the dunder method.
    """
    if MANAGER.config.py_version == 2:
        # Python 2's round() will always return float
        yield inference.InferenceResult.load_type(float)
        return
    round_func = _py2_round if MANAGER.config.py_version == 2 else round
    builtin_func_repr = "round"
    builtin_dunder_func_repr = "__" + builtin_func_repr + "__"
    if 0 > len(node.args) > 2 or len(node.keywords) > 0:
        raise inference.UseInferenceDefault()
    num_arg = node.args[0]
    try:
        ndigit_arg = node.args[1]
        ndigit_arg_iter = node.args[1].infer(context)
    except IndexError:
        ndigit_arg = None
        ndigit_arg_iter = [
            inference.InferenceResult.load_result(nodes.Const(0))
        ]
    for number, ndigits in utilities.infer_product(num_arg.infer(context),
                                                   ndigit_arg_iter):
        if number.status is False:
            # python 3's round() will delegate to __round__
            # only the type is known. Yield the return signature based on the input argument
            # since __round__ is overloaded in builtins.pyi
            if number.result_type is not None:
                dunder_method = number.result_type.dunder_lookup(
                    builtin_dunder_func_repr)
                if context.config.is_type_inference(
                ) and dunder_method is not None:
                    if isinstance(dunder_method, nodes.OverloadedFunc):
                        for res in dunder_method.get_return_type(
                                *node.args, context=context):
                            res += number + ndigits
                            yield res
                    else:
                        yield inference.InferenceResult.load_type(
                            dunder_method.get_return_type(),
                            inference_results=(number, ndigits))
                        return
        try:
            if isinstance(number.result, nodes.Const):
                ndigits_value = None if ndigits.status is False else ndigits.result.value
                result = round_func(number.result.value, ndigits_value)
                for res in inference.const_factory(result):
                    res += number + ndigits
                    yield res
                continue
            elif isinstance(number.result, nodes.ClassInstance):
                # if it's a class instance, try to find __float__, map arg and infer the return value
                try:
                    dunder_method = number.result.dunder_lookup(
                        builtin_dunder_func_repr)
                except exceptions.VariableNotExistStackError:
                    raise exceptions.DunderUnimplemented(
                        builtin_dunder_func_repr, number.result.target_cls)
                else:
                    # map the argument in abs() to the target dunder method
                    context.map_args_to_func(number.result,
                                             ndigit_arg,
                                             func_node=dunder_method)
                    for res in dunder_method.infer_return_value(context):
                        res += number + ndigits
                        yield res
                continue

        except ValueError:
            raise inference.UseInferenceDefault()
            pass