예제 #1
0
파일: finder.py 프로젝트: hattya/jedi
    def _remove_statements(self, stmt):
        """
        This is the part where statements are being stripped.

        Due to lazy evaluation, statements like a = func; b = a; b() have to be
        evaluated.
        """
        evaluator = self._evaluator
        types = []
        # Remove the statement docstr stuff for now, that has to be
        # implemented with the evaluator class.
        #if stmt.docstr:
        #res_new.append(stmt)

        check_instance = None
        if isinstance(stmt, er.InstanceElement) and stmt.is_class_var:
            check_instance = stmt.instance
            stmt = stmt.var

        types += evaluator.eval_statement(stmt,
                                          seek_name=unicode(self.name_str))

        if check_instance is not None:
            # class renames
            types = [
                er.InstanceElement(evaluator, check_instance, a, True)
                if isinstance(a, (er.Function, pr.Function)) else a
                for a in types
            ]
        return types
예제 #2
0
    def _remove_statements(self, stmt, name):
        """
        This is the part where statements are being stripped.

        Due to lazy evaluation, statements like a = func; b = a; b() have to be
        evaluated.
        """
        evaluator = self._evaluator
        types = []
        # Remove the statement docstr stuff for now, that has to be
        # implemented with the evaluator class.
        #if stmt.docstr:
            #res_new.append(stmt)

        check_instance = None
        if isinstance(stmt, er.InstanceElement) and stmt.is_class_var:
            check_instance = stmt.instance
            stmt = stmt.var

        types += evaluator.eval_statement(stmt, seek_name=unicode(self.name_str))

        # check for `except X as y` usages, because y needs to be instantiated.
        p = stmt.parent
        # TODO this looks really hacky, improve parser representation!
        if isinstance(p, pr.Flow) and p.command == 'except' \
                and p.inputs and p.inputs[0].as_names == [name]:
            # TODO check for types that are not classes and add it to the
            # static analysis report.
            types = list(chain.from_iterable(
                         evaluator.execute(t) for t in types))

        if check_instance is not None:
            # class renames
            types = [er.InstanceElement(evaluator, check_instance, a, True)
                     if isinstance(a, (er.Function, pr.Function))
                     else a for a in types]
        return types
예제 #3
0
def _check_array_additions(evaluator, compare_array, module, is_list):
    """
    Checks if a `pr.Array` has "add" statements:
    >>> a = [""]
    >>> a.append(1)
    """
    if not settings.dynamic_array_additions or isinstance(
            module, compiled.CompiledObject):
        return []

    def check_calls(calls, add_name):
        """
        Calls are processed here. The part before the call is searched and
        compared with the original Array.
        """
        result = []
        for c in calls:
            call_path = list(c.generate_call_path())
            call_path_simple = [
                unicode(n) if isinstance(n, pr.NamePart) else n
                for n in call_path
            ]
            separate_index = call_path_simple.index(add_name)
            if add_name == call_path_simple[-1] or separate_index == 0:
                # this means that there is no execution -> [].append
                # or the keyword is at the start -> append()
                continue
            backtrack_path = iter(call_path[:separate_index])

            position = c.start_pos
            scope = c.get_parent_until(pr.IsScope)

            found = evaluator.eval_call_path(backtrack_path, scope, position)
            if not compare_array in found:
                continue

            params = call_path[separate_index + 1]
            if not params.values:
                continue  # no params: just ignore it
            if add_name in ['append', 'add']:
                for param in params:
                    result += evaluator.eval_statement(param)
            elif add_name in ['insert']:
                try:
                    second_param = params[1]
                except IndexError:
                    continue
                else:
                    result += evaluator.eval_statement(second_param)
            elif add_name in ['extend', 'update']:
                for param in params:
                    iterators = evaluator.eval_statement(param)
                result += get_iterator_types(iterators)
        return result

    from jedi.evaluate import representation as er

    def get_execution_parent(element, *stop_classes):
        """ Used to get an Instance/FunctionExecution parent """
        if isinstance(element, Array):
            stmt = element._array.parent
        else:
            # is an Instance with an ArrayInstance inside
            stmt = element.var_args[0].var_args.parent
        if isinstance(stmt, er.InstanceElement):
            stop_classes = list(stop_classes) + [er.Function]
        return stmt.get_parent_until(stop_classes)

    temp_param_add = settings.dynamic_params_for_other_modules
    settings.dynamic_params_for_other_modules = False

    search_names = ['append', 'extend', 'insert'] if is_list else \
        ['add', 'update']
    comp_arr_parent = get_execution_parent(compare_array, er.FunctionExecution)

    possible_stmts = []
    res = []
    for n in search_names:
        try:
            possible_stmts += module.used_names[n]
        except KeyError:
            continue
        for stmt in possible_stmts:
            # Check if the original scope is an execution. If it is, one
            # can search for the same statement, that is in the module
            # dict. Executions are somewhat special in jedi, since they
            # literally copy the contents of a function.
            if isinstance(comp_arr_parent, er.FunctionExecution):
                stmt = comp_arr_parent. \
                    get_statement_for_position(stmt.start_pos)
                if stmt is None:
                    continue
            # InstanceElements are special, because they don't get copied,
            # but have this wrapper around them.
            if isinstance(comp_arr_parent, er.InstanceElement):
                stmt = er.InstanceElement(comp_arr_parent.instance, stmt)

            if evaluator.recursion_detector.push_stmt(stmt):
                # check recursion
                continue

            res += check_calls(helpers.scan_statement_for_calls(stmt, n), n)
            evaluator.recursion_detector.pop_stmt()
    # reset settings
    settings.dynamic_params_for_other_modules = temp_param_add
    return res