xref: /llvm-project/lldb/test/API/functionalities/rerun_and_expr/TestRerunAndExpr.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1"""
2Test that re-running a process from within the same target
3after rebuilding the executable flushes the scratch TypeSystems
4tied to that process.
5"""
6
7import lldb
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10from lldbsuite.test.decorators import *
11
12
13class TestRerunExpr(TestBase):
14    # FIXME: on Windows rebuilding the binary isn't enough to unload it
15    #        on progrem restart. One will have to try hard to evict
16    #        the module from the ModuleList (possibly including a call to
17    #        SBDebugger::MemoryPressureDetected.
18    @skipIfWindows
19    def test(self):
20        """
21        Tests whether re-launching a process without destroying
22        the owning target keeps invalid ASTContexts in the
23        scratch AST's importer.
24
25        We test this by:
26        1. Evaluating an expression to import 'struct Foo' into
27           the scratch AST
28        2. Change the definition of 'struct Foo' and rebuild the executable
29        3. Re-launch the process
30        4. Evaluate the same expression in (1). We expect to have only
31           the latest definition of 'struct Foo' in the scratch AST.
32        """
33        self.build(dictionary={"CXX_SOURCES": "main.cpp", "EXE": "a.out"})
34
35        exe = self.getBuildArtifact("a.out")
36        target = self.dbg.CreateTarget(exe)
37        target.BreakpointCreateBySourceRegex("return", lldb.SBFileSpec("rebuild.cpp"))
38        target.BreakpointCreateBySourceRegex("return", lldb.SBFileSpec("main.cpp"))
39        process = target.LaunchSimple(None, None, self.get_process_working_directory())
40
41        self.expect_expr(
42            "foo",
43            result_type="Foo",
44            result_children=[ValueCheck(name="m_val", value="42")],
45        )
46
47        # Delete the executable to force make to rebuild it.
48        remove_file(exe)
49        self.build(dictionary={"CXX_SOURCES": "rebuild.cpp", "EXE": "a.out"})
50
51        # Rerun program within the same target
52        process.Destroy()
53        process = target.LaunchSimple(None, None, self.get_process_working_directory())
54
55        self.expect_expr(
56            "foo",
57            result_type="Foo",
58            result_children=[
59                ValueCheck(
60                    name="Base", children=[ValueCheck(name="m_base_val", value="42")]
61                ),
62                ValueCheck(name="m_derived_val", value="137"),
63            ],
64        )
65
66        self.filecheck("target module dump ast", __file__)
67
68        # The new definition 'struct Foo' is in the scratch AST
69        # CHECK:      |-CXXRecordDecl {{.*}} struct Foo definition
70        # CHECK:      | |-public 'Base'
71        # CHECK-NEXT: | `-FieldDecl {{.*}} m_derived_val 'int'
72        # CHECK-NEXT: `-CXXRecordDecl {{.*}} struct Base definition
73        # CHECK:        `-FieldDecl {{.*}} m_base_val 'int'
74
75        # ...but the original definition of 'struct Foo' is not in the scratch AST anymore
76        # CHECK-NOT: FieldDecl {{.*}} m_val 'int'
77