Beispiel #1
0
def _index_name_nodes(
        index: str, for_node: astroid.For
) -> List[Union[astroid.AssignName, astroid.Name]]:
    """Return a list of <index> AssignName and Name nodes contained in the body of <for_node>."""
    return [
        name_node for name_node in for_node.nodes_of_class((astroid.AssignName,
                                                            astroid.Name))
        if name_node.name == index and name_node != for_node.target
    ]
Beispiel #2
0
    def visit_for(self, node: astroid.For) -> None:
        old_curr = self._current_block
        old_curr.add_statement(node.iter)
        node.cfg_block = old_curr

        # Handle "test" block
        test_block = self._current_cfg.create_block()
        test_block.add_statement(node.target)
        self._current_cfg.link_or_merge(old_curr, test_block)

        after_for_block = self._current_cfg.create_block()

        # step into for
        self._control_boundaries.append((node, {
            astroid.Break.__name__: after_for_block,
            astroid.Continue.__name__: test_block
        }))

        # Handle "body" branch
        body_block = self._current_cfg.create_block(test_block)
        self._current_block = body_block
        for child in node.body:
            child.accept(self)
        end_body = self._current_block
        self._current_cfg.link_or_merge(end_body, test_block)

        # step out of for
        self._control_boundaries.pop()

        # Handle "else" branch
        else_block = self._current_cfg.create_block(test_block)
        self._current_block = else_block
        for child in node.orelse:
            child.accept(self)
        end_else = self._current_block

        self._current_cfg.link_or_merge(end_else, after_for_block)
        self._current_block = after_for_block
def _index_name_nodes(index: str, for_node: astroid.For) -> List[Union[astroid.AssignName, astroid.Name]]:
    """Return a list of <index> AssignName and Name nodes contained in the body of <for_node>."""
    return [name_node for name_node in for_node.nodes_of_class((astroid.AssignName, astroid.Name))
            if name_node.name == index and name_node != for_node.target]
    def _check_consider_using_enumerate(self, node: astroid.For) -> None:
        """Emit a convention whenever range and len are used for indexing."""
        # Verify that we have a `range([start], len(...), [stop])` call and
        # that the object which is iterated is used as a subscript in the
        # body of the for.

        # Is it a proper range call?
        if not isinstance(node.iter, astroid.Call):
            return
        if not self._is_builtin(node.iter.func, "range"):
            return
        if not node.iter.args:
            return
        is_constant_zero = (isinstance(node.iter.args[0], astroid.Const)
                            and node.iter.args[0].value == 0)
        if len(node.iter.args) == 2 and not is_constant_zero:
            return
        if len(node.iter.args) > 2:
            return

        # Is it a proper len call?
        if not isinstance(node.iter.args[-1], astroid.Call):
            return
        second_func = node.iter.args[-1].func
        if not self._is_builtin(second_func, "len"):
            return
        len_args = node.iter.args[-1].args
        if not len_args or len(len_args) != 1:
            return
        iterating_object = len_args[0]
        if isinstance(iterating_object, astroid.Name):
            expected_subscript_val_type = astroid.Name
        elif isinstance(iterating_object, astroid.Attribute):
            expected_subscript_val_type = astroid.Attribute
        else:
            return
        # If we're defining __iter__ on self, enumerate won't work
        scope = node.scope()
        if (isinstance(iterating_object, astroid.Name)
                and iterating_object.name == "self"
                and scope.name == "__iter__"):
            return

        # Verify that the body of the for loop uses a subscript
        # with the object that was iterated. This uses some heuristics
        # in order to make sure that the same object is used in the
        # for body.
        for child in node.body:
            for subscript in child.nodes_of_class(astroid.Subscript):
                subscript = cast(astroid.Subscript, subscript)
                if not isinstance(subscript.value,
                                  expected_subscript_val_type):
                    continue

                value = subscript.slice
                if not isinstance(value, astroid.Name):
                    continue
                if subscript.value.scope() != node.scope():
                    # Ignore this subscript if it's not in the same
                    # scope. This means that in the body of the for
                    # loop, another scope was created, where the same
                    # name for the iterating object was used.
                    continue
                if value.name == node.target.name and (
                        isinstance(subscript.value, astroid.Name)
                        and iterating_object.name == subscript.value.name
                        or isinstance(subscript.value, astroid.Attribute) and
                        iterating_object.attrname == subscript.value.attrname):
                    self.add_message("consider-using-enumerate", node=node)
                    return