def _filter_stmts(self, stmts, frame, offset):
        """Filter the given list of statements to remove ignorable statements.

        If self is not a frame itself and the name is found in the inner
        frame locals, statements will be filtered to remove ignorable
        statements according to self's location.

        :param stmts: The statements to filter.
        :type stmts: list(NodeNG)

        :param frame: The frame that all of the given statements belong to.
        :type frame: NodeNG

        :param offset: The line offset to filter statements up to.
        :type offset: int

        :returns: The filtered statements.
        :rtype: list(NodeNG)
        """
        # if offset == -1, my actual frame is not the inner frame but its parent
        #
        # class A(B): pass
        #
        # we need this to resolve B correctly
        if offset == -1:
            myframe = self.frame().parent.frame()
        else:
            myframe = self.frame()
            # If the frame of this node is the same as the statement
            # of this node, then the node is part of a class or
            # a function definition and the frame of this node should be the
            # the upper frame, not the frame of the definition.
            # For more information why this is important,
            # see Pylint issue #295.
            # For example, for 'b', the statement is the same
            # as the frame / scope:
            #
            # def test(b=1):
            #     ...

            if self.statement() is myframe and myframe.parent:
                myframe = myframe.parent.frame()
        mystmt = self.statement()
        # line filtering if we are in the same frame
        #
        # take care node may be missing lineno information (this is the case for
        # nodes inserted for living objects)
        if myframe is frame and mystmt.fromlineno is not None:
            assert mystmt.fromlineno is not None, mystmt
            mylineno = mystmt.fromlineno + offset
        else:
            # disabling lineno filtering
            mylineno = 0

        _stmts = []
        _stmt_parents = []
        statements = self._get_filtered_node_statements(stmts)

        for node, stmt in statements:
            # line filtering is on and we have reached our location, break
            if stmt.fromlineno > mylineno > 0:
                break
            # Ignore decorators with the same name as the
            # decorated function
            # Fixes issue #375
            if mystmt is stmt and is_from_decorator(self):
                continue
            assert hasattr(node, "assign_type"), (
                node,
                node.scope(),
                node.scope().locals,
            )
            assign_type = node.assign_type()
            if node.has_base(self):
                break

            _stmts, done = assign_type._get_filtered_stmts(self, node, _stmts, mystmt)
            if done:
                break

            optional_assign = assign_type.optional_assign
            if optional_assign and assign_type.parent_of(self):
                # we are inside a loop, loop var assignment is hiding previous
                # assignment
                _stmts = [node]
                _stmt_parents = [stmt.parent]
                continue

            # XXX comment various branches below!!!
            try:
                pindex = _stmt_parents.index(stmt.parent)
            except ValueError:
                pass
            else:
                # we got a parent index, this means the currently visited node
                # is at the same block level as a previously visited node
                if _stmts[pindex].assign_type().parent_of(assign_type):
                    # both statements are not at the same block level
                    continue
                # if currently visited node is following previously considered
                # assignment and both are not exclusive, we can drop the
                # previous one. For instance in the following code ::
                #
                #   if a:
                #     x = 1
                #   else:
                #     x = 2
                #   print x
                #
                # we can't remove neither x = 1 nor x = 2 when looking for 'x'
                # of 'print x'; while in the following ::
                #
                #   x = 1
                #   x = 2
                #   print x
                #
                # we can remove x = 1 when we see x = 2
                #
                # moreover, on loop assignment types, assignment won't
                # necessarily be done if the loop has no iteration, so we don't
                # want to clear previous assignments if any (hence the test on
                # optional_assign)
                if not (optional_assign or are_exclusive(_stmts[pindex], node)):
                    if (
                        # In case of partial function node, if the statement is different
                        # from the origin function then it can be deleted otherwise it should
                        # remain to be able to correctly infer the call to origin function.
                        not node.is_function
                        or node.qname() != "PartialFunction"
                        or node.name != _stmts[pindex].name
                    ):
                        del _stmt_parents[pindex]
                        del _stmts[pindex]
            if isinstance(node, AssignName):
                if not optional_assign and stmt.parent is mystmt.parent:
                    _stmts = []
                    _stmt_parents = []
            elif isinstance(node, DelName):
                _stmts = []
                _stmt_parents = []
                continue
            if not are_exclusive(self, node):
                _stmts.append(node)
                _stmt_parents.append(stmt.parent)
        return _stmts
Filter the given list of statements to remove ignorable statements.

        If self is not a frame itself and the name is found in the inner
        frame locals, statements will be filtered to remove ignorable
        statements according to self's location.

        :param stmts: The statements to filter.
        :type stmts: list(NodeNG)

        :param frame: The frame that all of the given statements belong to.
        :type frame: NodeNG

        :param offset: The line offset to filter statements up to.
        :type offset: int

        :returns: The filtered statements.
        :rtype: list(NodeNG)