コード例 #1
0
    def test_data_dependency_3(self):
        # Transitive explicit (full cover) dependencies
        def func() -> int:
            foo = 1
            result = 1 + foo
            return result

        expected_instructions = [
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # result = 1 + foo
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_FAST", arg="foo"),
            Instr("BINARY_ADD"),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ]

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #2
0
    def test_simple_control_dependency_2(self):
        # If condition evaluated to false, with two relevant variables (but no influence on result)
        def func() -> int:
            foo = 1
            bar = 2
            result = 3

            if foo == bar:
                result = 1

            return result

        init_basic_block = BasicBlock([
            # result = 3
            Instr("LOAD_CONST", arg=3),
            Instr("STORE_FAST", arg="result"),
        ])
        return_basic_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(init_basic_block)
        expected_instructions.extend(return_basic_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #3
0
    def test_simple_control_dependency_4(self):
        # If-elif-else with else branch true
        def func() -> int:
            foo = 1
            bar = 2

            if foo == bar:
                result = 1
            elif foo > bar:
                result = 2
            else:
                result = 3

            return result

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        else_block = BasicBlock([
            # result = 3
            Instr("LOAD_CONST", arg=3),
            Instr("STORE_FAST", arg="result")
        ])
        elif_cond = BasicBlock([
            # elif foo == 1:
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.GT),
            Instr("POP_JUMP_IF_FALSE", arg=else_block),
        ])
        if_cond = BasicBlock([
            # if foo == bar
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.EQ),
            Instr("POP_JUMP_IF_FALSE", arg=elif_cond),
        ])
        init_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # bar = 2
            Instr("LOAD_CONST", arg=2),
            Instr("STORE_FAST", arg="bar"),
        ])

        expected_instructions = []
        expected_instructions.extend(init_block)
        expected_instructions.extend(if_cond)
        expected_instructions.extend(elif_cond)
        expected_instructions.extend(else_block)
        expected_instructions.extend(return_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #4
0
    def test_builtin_addresses(self):
        def func():
            test_dict = {1: "one", 2: "two"}
            # noinspection PyListCreation
            test_list = [1, 2]

            test_list.append(3)

            result = test_dict.get(1)
            return result

        function_block = BasicBlock([
            # test_dict = {1: "one", 2: "two"}
            Instr("LOAD_CONST", arg="one"),
            Instr("LOAD_CONST", arg="two"),
            Instr("LOAD_CONST", arg=(1, 2)),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("STORE_FAST", arg="test_dict"),

            # result = test_dict.get(1)
            Instr("LOAD_FAST", arg="test_dict"),
            Instr("LOAD_METHOD", arg="get"),
            Instr("LOAD_CONST", arg=1),
            Instr("CALL_METHOD", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_builtin_addresses")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #5
0
    def test_nested_class(self):
        def func():
            # STORE_DEREF, LOAD_CLOSURE, LOAD_CLASSDEREF
            x = []

            class NestedClass:
                y = x

            class_attr = NestedClass.y

            result = class_attr
            return result

        freevar_x = FreeVar("x")
        cellvar_x = CellVar("x")
        function_block = BasicBlock([
            # x = []
            Instr("BUILD_LIST", arg=0),
            Instr("STORE_DEREF", arg=cellvar_x),

            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # class_attr = NestedClass.y
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("LOAD_ATTR", arg="y"),
            Instr("STORE_FAST", arg="class_attr"),

            # result = class_attr
            Instr("LOAD_FAST", arg="class_attr"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # y = x
            Instr("LOAD_CLASSDEREF", arg=freevar_x),
            Instr("STORE_NAME", arg="y"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_nested_class")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #6
0
    def test_simple_loop(self):
        def func():
            result = 0
            for i in range(0, 3):
                result += i
            return result

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        loop_header = BasicBlock([
            Instr("FOR_ITER", arg=return_block),
        ])
        loop_block = BasicBlock([
            # result += i
            Instr("STORE_FAST", arg="i"),
            Instr("LOAD_FAST", arg="result"),
            Instr("LOAD_FAST", arg="i"),
            Instr("INPLACE_ADD"),
            Instr("STORE_FAST", arg="result"),
            Instr("JUMP_ABSOLUTE", arg=loop_header),
        ])
        loop_setup = BasicBlock([
            # for i in range(0, 3):
            Instr("LOAD_GLOBAL", arg="range"),
            Instr("LOAD_CONST", arg=0),
            Instr("LOAD_CONST", arg=3),
            Instr("CALL_FUNCTION", arg=2),
            Instr("GET_ITER"),
        ])
        init_block = BasicBlock([
            Instr("LOAD_CONST", arg=0),
            Instr("STORE_FAST", arg="result"),
        ])

        expected_instructions = []
        expected_instructions.extend(init_block)
        expected_instructions.extend(loop_setup)
        expected_instructions.extend(loop_header)
        expected_instructions.extend(loop_block)
        expected_instructions.extend(return_block)

        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_simple_loop")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #7
0
    def test_simple_control_dependency_1(self):
        # If condition evaluated to true, with relevant variable foo
        def func() -> int:
            foo = 1
            result = 3

            if foo == 1:
                result = 1

            return result

        return_basic_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        if_basic_block = BasicBlock([
            # result = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="result"),
        ])
        init_basic_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # if foo == 1
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_CONST", arg=1),
            Instr("COMPARE_OP", arg=Compare.EQ),
            Instr("POP_JUMP_IF_FALSE", arg=return_basic_block),
        ])

        expected_instructions = []
        expected_instructions.extend(init_basic_block)
        expected_instructions.extend(if_basic_block)
        expected_instructions.extend(return_basic_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #8
0
    def test_with_extended_arg(self):
        def func():
            p = [1, 2, 3, 4, 5, 6]
            # noinspection PyUnusedLocal
            unused = p
            q, r, *s, t = p  # With extended argument

            result = q, r
            return result

        module_block = BasicBlock([
            # p = [1, 2, 3, 4, 5, 6]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("LOAD_CONST", arg=4),
            Instr("LOAD_CONST", arg=5),
            Instr("LOAD_CONST", arg=6),
            Instr("BUILD_LIST", arg=6),
            Instr("STORE_FAST", arg="p"),
            # q, r, *s, t = p
            Instr("LOAD_FAST", arg="p"),
            # Instr("EXTENDED_ARG", arg=1),  # EXTENDED_ARG can not be in a slice
            Instr("UNPACK_EX", arg=258),
            Instr("STORE_FAST", arg="q"),
            Instr("STORE_FAST", arg="r"),

            # result = q
            Instr("LOAD_FAST", arg="q"),
            Instr("LOAD_FAST", arg="r"),
            Instr("BUILD_TUPLE", arg=2),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_with_extended_arg")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #9
0
    def test_data_dependency_1(self):
        # Implicit data dependency at return, explicit (full cover) for result
        def func() -> int:
            result = 1
            return result

        expected_instructions = [
            # result = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ]

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #10
0
    def test_mod_untraced_object(self):
        def func():
            lst = [('foo', '3'), ('bar', '1'), ('foobar', '2')]
            lst.sort(
            )  # This is incorrectly excluded, since it is not known that the method modifies the list

            result = lst
            return result

        function_block = BasicBlock([
            # lst = [('foo', '3'), ('bar', '1'), ('foobar', '2')]
            Instr("LOAD_CONST", arg=('foo', '3')),
            Instr("LOAD_CONST", arg=('bar', '1')),
            Instr("LOAD_CONST", arg=('foobar', '2')),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_FAST", arg="lst"),

            # lst.sort()
            # This is incorrectly excluded, since it is not known that the method modifies the list
            Instr("LOAD_FAST", arg="lst"),
            Instr("LOAD_METHOD", arg="sort"),
            Instr("CALL_METHOD", arg=0),
            Instr("POP_TOP"),

            # result = lst
            Instr("LOAD_FAST", arg="lst"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        dynamic_slice = slice_function_at_return(
            func.__code__, test_name="test_mod_untraced_object")
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #11
0
    def test_data_dependency_composite(self):
        # Composite type dependencies, which are way to broad
        def func():
            # noinspection PyListCreation
            foo_list = [1, 2,
                        3]  # the only list operation which should be included
            foo_list.append(
                4
            )  # should no be included, and is not included (good and limitation at the same time)
            foo_list += [5]  # should no be included, but is
            foo_list[2:3] = [0, 0]  # should no be included, but is

            result = foo_list[0]  # correctly included
            return result  # correctly included

        expected_instructions = [
            # foo_list = [1, 2, 3]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_FAST", arg="foo_list"),

            # result = foo_list[0]
            Instr("LOAD_FAST", arg="foo_list"),
            Instr("LOAD_CONST", arg=0),
            Instr("BINARY_SUBSCR"),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ]

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #12
0
    def test_lambda(self):
        def func():
            x = lambda a: a + 10

            result = x(1)
            return result

        function_block = BasicBlock([
            # x = lambda a: a + 10
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_lambda.<locals>.func.<locals>.<lambda>"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="x"),

            # result = x(1)
            Instr("LOAD_FAST", arg="x"),
            Instr("LOAD_CONST", arg=1),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        lambda_block = BasicBlock([
            # lambda a: a + 10
            Instr("LOAD_FAST", arg="a"),
            Instr("LOAD_CONST", arg=10),
            Instr("BINARY_ADD"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(lambda_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_lambda")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #13
0
    def test_dunder_definition(self):
        def func():
            class NestedClass:
                def __init__(
                    self
                ):  # Definition of dunder methods wrongly excluded, these are not explicitly loaded
                    self.x = 1

            result = NestedClass()
            return result

        function_block = BasicBlock([
            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # result = NestedClass()
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # Definition of dunder methods are wrongly excluded, since these are not explicitly loaded
            # def __init__(self):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr(
                "LOAD_CONST",
                arg=
                "IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
                "func.<locals>.NestedClass.__init__"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="__init__"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        init_block = BasicBlock([
            # self.x = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        expected_instructions.extend(init_block)
        dynamic_slice = slice_function_at_return(
            func.__code__, test_name="test_dunder_definition")
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #14
0
    def test_exception(self):
        # Exception
        def func():
            foo = 1
            bar = 0

            try:
                result = 0 / 0
            except ZeroDivisionError:
                result = foo + bar

            return result

        self.assertEqual(func(), 1)

        dummy_block = BasicBlock([])

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        try_block = BasicBlock([
            # result = foo / bar <- did somehow effect slicing criterion...
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("BINARY_TRUE_DIVIDE"),

            # except ZeroDivisionError:
            Instr("DUP_TOP"),
            Instr("LOAD_GLOBAL", arg="ZeroDivisionError"),
            Instr("COMPARE_OP", arg=Compare.EXC_MATCH),
            Instr("POP_JUMP_IF_FALSE", arg=dummy_block),
        ])
        except_block = BasicBlock([
            # result = foo + bar
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("BINARY_ADD"),
            Instr("STORE_FAST", arg="result"),
            Instr("JUMP_FORWARD", arg=dummy_block),
        ])
        function_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST",
                  arg=1),  # <- excluded because no stack simulation
            Instr("STORE_FAST", arg="foo"),
            # bar = 0
            Instr("LOAD_CONST",
                  arg=0),  # <- excluded because no stack simulation
            Instr("STORE_FAST", arg="bar"),

            # try:
            # Instr("SETUP_FINALLY", arg=try_block),
        ])

        expected_instructions = []
        expected_instructions.extend(return_block)
        expected_instructions.extend(except_block)
        expected_instructions.extend(function_block)
        expected_instructions.extend(try_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #15
0
    def test_object_modification_call(self):
        def func():
            class NestedClass:
                def __init__(self):
                    self.x = 1

                def inc_x(self):
                    self.x = self.x + 1

            ob = NestedClass()
            ob.inc_x()

            result = ob.x
            return result

        function_block = BasicBlock([
            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # ob = NestedClass()
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="ob"),

            # ob.inc_x()
            Instr("LOAD_FAST", arg="ob"),
            Instr("LOAD_METHOD", arg="inc_x"),
            Instr("CALL_METHOD", arg=0),

            # result = ob.x
            Instr("LOAD_FAST", arg="ob"),
            Instr("LOAD_ATTR", arg="x"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # Definition of dunder methods are wrongly excluded, since these are not explicitly loaded
            # def __init__(self):
            # Instr("LOAD_CONST", arg=dummy_code_object),
            # Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
            #                         "func.<locals>.NestedClass.__init__"),
            # Instr("MAKE_FUNCTION", arg=0),
            # Instr("STORE_NAME", arg="__init__"),

            # def inc_x(self):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
                                    "func.<locals>.NestedClass.inc_x"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="inc_x"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        init_block = BasicBlock([
            # self.x = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        inc_x_block = BasicBlock([
            # self.x = self.x + 1
            Instr("LOAD_FAST", arg="self"),
            Instr("LOAD_ATTR", arg="x"),
            Instr("LOAD_CONST", arg=1),
            Instr("BINARY_ADD"),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),

            # This "None return" is not included, because the return value is not used
            # Instr("LOAD_CONST", arg=None),
            # Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        expected_instructions.extend(init_block)
        expected_instructions.extend(inc_x_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_object_modification_call")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #16
0
    def test_nested_class_2(self):
        # Critical test to ensure that the attributes converted to variables
        # are taken from the correct scope.

        def func():
            # STORE_DEREF, LOAD_CLOSURE, LOAD_CLASSDEREF
            x1 = [1]
            x2 = [2]

            class Bar:
                foo = x1  # included!

                class Foo:
                    foo = x2  # NOT included
                    y = x2  # included

                y = Foo.y  # NOT included

            class_attr = Bar.foo
            class_attr2 = Bar.Foo.y

            result = class_attr + class_attr2
            return result

        freevar_x1 = FreeVar("x1")
        cellvar_x1 = CellVar("x1")
        freevar_x2 = FreeVar("x2")
        cellvar_x2 = CellVar("x2")
        function_block = BasicBlock([
            # x1 = [1]
            Instr("LOAD_CONST", arg=1),
            Instr("BUILD_LIST", arg=1),
            Instr("STORE_DEREF", arg=cellvar_x1),
            # x2 = [2]
            Instr("LOAD_CONST", arg=2),
            Instr("BUILD_LIST", arg=1),
            Instr("STORE_DEREF", arg=cellvar_x2),

            # class Bar:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x1),
            Instr("LOAD_CLOSURE", arg=freevar_x2),
            Instr("BUILD_TUPLE", arg=2),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Bar"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="Bar"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="Bar"),

            # class_attr = Bar.y
            Instr("LOAD_FAST", arg="Bar"),
            Instr("LOAD_ATTR", arg="foo"),
            Instr("STORE_FAST", arg="class_attr"),

            # class_attr2 = Bar.Foo.y
            Instr("LOAD_FAST", arg="Bar"),
            Instr("LOAD_ATTR", arg="Foo"),
            Instr("LOAD_ATTR", arg="y"),
            Instr("STORE_FAST", arg="class_attr2"),

            # result = class_attr + class_attr2
            Instr("LOAD_FAST", arg="class_attr"),
            Instr("LOAD_FAST", arg="class_attr2"),
            Instr("BINARY_ADD"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        bar_block = BasicBlock([
            # class Foo:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x2),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="Foo"),

            # foo = x1
            Instr("LOAD_CLASSDEREF", arg=freevar_x1),
            Instr("STORE_NAME", arg="foo"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        foo_block = BasicBlock([
            # y = x2
            Instr("LOAD_CLASSDEREF", arg=freevar_x2),
            Instr("STORE_NAME", arg="y"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(foo_block)
        expected_instructions.extend(bar_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_nested_class_2")
        self.assertEqual(func(), [1, 2])
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))