xref: /llvm-project/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
199451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
299451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
399451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht"""
699451b44SJordan RupprechtThis test ensures that we only create Clang AST nodes in our module AST
799451b44SJordan Rupprechtwhen we actually need them.
899451b44SJordan Rupprecht
999451b44SJordan RupprechtAll tests in this file behave like this:
1099451b44SJordan Rupprecht  1. Use LLDB to do something (expression evaluation, breakpoint setting, etc.).
1199451b44SJordan Rupprecht  2. Check that certain Clang AST nodes were not loaded during the previous
1299451b44SJordan Rupprecht     step.
1399451b44SJordan Rupprecht"""
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht
16*2238dcc3SJonas Devlieghereclass TestCase(TestBase):
1799451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprecht    def setUp(self):
2099451b44SJordan Rupprecht        TestBase.setUp(self)
2199451b44SJordan Rupprecht        # Only build this test once.
2299451b44SJordan Rupprecht        self.build()
2399451b44SJordan Rupprecht
2499451b44SJordan Rupprecht    # Clang declaration kind we are looking for.
2599451b44SJordan Rupprecht    class_decl_kind = "CXXRecordDecl"
2699451b44SJordan Rupprecht    # FIXME: This shouldn't be a CXXRecordDecl, but that's how we model
2799451b44SJordan Rupprecht    # structs in Clang.
2899451b44SJordan Rupprecht    struct_decl_kind = "CXXRecordDecl"
2999451b44SJordan Rupprecht
3099451b44SJordan Rupprecht    # The decls we use in this program in the format that
3199451b44SJordan Rupprecht    # decl_in_line and decl_completed_in_line expect (which is a pair of
3299451b44SJordan Rupprecht    # node type and the unqualified declaration name.
3399451b44SJordan Rupprecht    struct_first_member_decl = [struct_decl_kind, "StructFirstMember"]
3499451b44SJordan Rupprecht    struct_behind_ptr_decl = [struct_decl_kind, "StructBehindPointer"]
3599451b44SJordan Rupprecht    struct_behind_ref_decl = [struct_decl_kind, "StructBehindRef"]
3699451b44SJordan Rupprecht    struct_member_decl = [struct_decl_kind, "StructMember"]
3799451b44SJordan Rupprecht    some_struct_decl = [struct_decl_kind, "SomeStruct"]
3899451b44SJordan Rupprecht    other_struct_decl = [struct_decl_kind, "OtherStruct"]
3999451b44SJordan Rupprecht    class_in_namespace_decl = [class_decl_kind, "ClassInNamespace"]
4099451b44SJordan Rupprecht    class_we_enter_decl = [class_decl_kind, "ClassWeEnter"]
4199451b44SJordan Rupprecht    class_member_decl = [struct_decl_kind, "ClassMember"]
4234c697c8SRaphael Isemann    class_static_member_decl = [struct_decl_kind, "StaticClassMember"]
4399451b44SJordan Rupprecht    unused_class_member_decl = [struct_decl_kind, "UnusedClassMember"]
4499451b44SJordan Rupprecht    unused_class_member_ptr_decl = [struct_decl_kind, "UnusedClassMemberPtr"]
4599451b44SJordan Rupprecht
4699451b44SJordan Rupprecht    def assert_no_decls_loaded(self):
4799451b44SJordan Rupprecht        """
4899451b44SJordan Rupprecht        Asserts that no known declarations in this test are loaded
4999451b44SJordan Rupprecht        into the module's AST.
5099451b44SJordan Rupprecht        """
5199451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.struct_first_member_decl)
5299451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.struct_behind_ptr_decl)
5399451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.struct_behind_ref_decl)
5499451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.struct_member_decl)
5599451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.some_struct_decl)
5699451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.other_struct_decl)
5799451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.class_in_namespace_decl)
5899451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.class_member_decl)
5934c697c8SRaphael Isemann        self.assert_decl_not_loaded(self.class_static_member_decl)
6099451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.unused_class_member_decl)
6199451b44SJordan Rupprecht
6299451b44SJordan Rupprecht    def get_ast_dump(self):
6399451b44SJordan Rupprecht        """Returns the dumped Clang AST of the module as a string"""
6499451b44SJordan Rupprecht        res = lldb.SBCommandReturnObject()
6599451b44SJordan Rupprecht        ci = self.dbg.GetCommandInterpreter()
66*2238dcc3SJonas Devlieghere        ci.HandleCommand("target modules dump ast a.out", res)
6799451b44SJordan Rupprecht        self.assertTrue(res.Succeeded())
6899451b44SJordan Rupprecht        return res.GetOutput()
6999451b44SJordan Rupprecht
7099451b44SJordan Rupprecht    def decl_in_line(self, line, decl):
7199451b44SJordan Rupprecht        """
7299451b44SJordan Rupprecht        Returns true iff the given line declares the given Clang decl.
7399451b44SJordan Rupprecht        The line is expected to be in the form of Clang's AST dump.
7499451b44SJordan Rupprecht        """
7599451b44SJordan Rupprecht        line = line.rstrip() + "\n"
7699451b44SJordan Rupprecht        decl_kind = "-" + decl[0] + " "
7799451b44SJordan Rupprecht        # Either the decl is somewhere in the line or at the end of
7899451b44SJordan Rupprecht        # the line.
7999451b44SJordan Rupprecht        decl_name = " " + decl[1] + " "
8099451b44SJordan Rupprecht        decl_name_eol = " " + decl[1] + "\n"
8199451b44SJordan Rupprecht        if not decl_kind in line:
8299451b44SJordan Rupprecht            return False
8399451b44SJordan Rupprecht        return decl_name in line or decl_name_eol in line
8499451b44SJordan Rupprecht
8599451b44SJordan Rupprecht    def decl_completed_in_line(self, line, decl):
8699451b44SJordan Rupprecht        """
8799451b44SJordan Rupprecht        Returns true iff the given line declares the given Clang decl and
8899451b44SJordan Rupprecht        the decl was completed (i.e., it has no undeserialized declarations
8999451b44SJordan Rupprecht        in it).
9099451b44SJordan Rupprecht        """
91*2238dcc3SJonas Devlieghere        return (
92*2238dcc3SJonas Devlieghere            self.decl_in_line(line, decl)
93*2238dcc3SJonas Devlieghere            and not "<undeserialized declarations>" in line
94*2238dcc3SJonas Devlieghere        )
9599451b44SJordan Rupprecht
9699451b44SJordan Rupprecht    # The following asserts are used for checking if certain Clang declarations
9799451b44SJordan Rupprecht    # were loaded or not since the target was created.
9899451b44SJordan Rupprecht
9999451b44SJordan Rupprecht    def assert_decl_loaded(self, decl):
10099451b44SJordan Rupprecht        """
10199451b44SJordan Rupprecht        Asserts the given decl is currently loaded.
10299451b44SJordan Rupprecht        Note: This test is about checking that types/declarations are not
10399451b44SJordan Rupprecht        loaded. If this assert fails it is usually fine to turn it into a
10499451b44SJordan Rupprecht        assert_decl_not_loaded or assert_decl_not_completed assuming LLDB's
10599451b44SJordan Rupprecht        functionality has not suffered by not loading this declaration.
10699451b44SJordan Rupprecht        """
10799451b44SJordan Rupprecht        ast = self.get_ast_dump()
10899451b44SJordan Rupprecht        found = False
10999451b44SJordan Rupprecht        for line in ast.splitlines():
11099451b44SJordan Rupprecht            if self.decl_in_line(line, decl):
11199451b44SJordan Rupprecht                found = True
112*2238dcc3SJonas Devlieghere                self.assertTrue(
113*2238dcc3SJonas Devlieghere                    self.decl_completed_in_line(line, decl),
114*2238dcc3SJonas Devlieghere                    "Should have called assert_decl_not_completed",
115*2238dcc3SJonas Devlieghere                )
116*2238dcc3SJonas Devlieghere        self.assertTrue(
117*2238dcc3SJonas Devlieghere            found, "Declaration no longer loaded " + str(decl) + ".\nAST:\n" + ast
118*2238dcc3SJonas Devlieghere        )
11999451b44SJordan Rupprecht
12099451b44SJordan Rupprecht    def assert_decl_not_completed(self, decl):
12199451b44SJordan Rupprecht        """
12299451b44SJordan Rupprecht        Asserts that the given decl is currently not completed in the module's
12399451b44SJordan Rupprecht        AST. It may be loaded but then can can only contain undeserialized
12499451b44SJordan Rupprecht        declarations.
12599451b44SJordan Rupprecht        """
12699451b44SJordan Rupprecht        ast = self.get_ast_dump()
12799451b44SJordan Rupprecht        found = False
12899451b44SJordan Rupprecht        for line in ast.splitlines():
12999451b44SJordan Rupprecht            error_msg = "Unexpected completed decl: '" + line + "'.\nAST:\n" + ast
13099451b44SJordan Rupprecht            self.assertFalse(self.decl_completed_in_line(line, decl), error_msg)
13199451b44SJordan Rupprecht
13299451b44SJordan Rupprecht    def assert_decl_not_loaded(self, decl):
13399451b44SJordan Rupprecht        """
13499451b44SJordan Rupprecht        Asserts that the given decl is currently not loaded in the module's
13599451b44SJordan Rupprecht        AST.
13699451b44SJordan Rupprecht        """
13799451b44SJordan Rupprecht        ast = self.get_ast_dump()
13899451b44SJordan Rupprecht        found = False
13999451b44SJordan Rupprecht        for line in ast.splitlines():
14099451b44SJordan Rupprecht            error_msg = "Unexpected loaded decl: '" + line + "'\nAST:\n" + ast
14199451b44SJordan Rupprecht            self.assertFalse(self.decl_in_line(line, decl), error_msg)
14299451b44SJordan Rupprecht
14399451b44SJordan Rupprecht    def clean_setup(self, location):
14499451b44SJordan Rupprecht        """
14599451b44SJordan Rupprecht        Runs to the line with the source line with the given location string
14699451b44SJordan Rupprecht        and ensures that our module AST is empty.
14799451b44SJordan Rupprecht        """
148*2238dcc3SJonas Devlieghere        lldbutil.run_to_source_breakpoint(
149*2238dcc3SJonas Devlieghere            self, "// Location: " + location, lldb.SBFileSpec("main.cpp")
150*2238dcc3SJonas Devlieghere        )
15199451b44SJordan Rupprecht        # Make sure no declarations are loaded initially.
15299451b44SJordan Rupprecht        self.assert_no_decls_loaded()
15399451b44SJordan Rupprecht
15499451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
15599451b44SJordan Rupprecht    def test_arithmetic_expression_in_main(self):
15699451b44SJordan Rupprecht        """Runs a simple arithmetic expression which should load nothing."""
15799451b44SJordan Rupprecht        self.clean_setup(location="multiple locals function")
15899451b44SJordan Rupprecht
159*2238dcc3SJonas Devlieghere        self.expect("expr 1 + (int)2.0", substrs=["(int) $0"])
16099451b44SJordan Rupprecht
16199451b44SJordan Rupprecht        # This should not have loaded any decls.
16299451b44SJordan Rupprecht        self.assert_no_decls_loaded()
16399451b44SJordan Rupprecht
16499451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
16599451b44SJordan Rupprecht    def test_printing_local_variable_in_other_struct_func(self):
16699451b44SJordan Rupprecht        """
16799451b44SJordan Rupprecht        Prints a local variable and makes sure no unrelated types are loaded.
16899451b44SJordan Rupprecht        """
16999451b44SJordan Rupprecht        self.clean_setup(location="other struct function")
17099451b44SJordan Rupprecht
171*2238dcc3SJonas Devlieghere        self.expect("expr other_struct_var", substrs=["(OtherStruct) $0"])
17299451b44SJordan Rupprecht        # The decl we run on was loaded.
17399451b44SJordan Rupprecht        self.assert_decl_loaded(self.other_struct_decl)
17499451b44SJordan Rupprecht
17599451b44SJordan Rupprecht        # This should not have loaded anything else.
17699451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.some_struct_decl)
17799451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.class_in_namespace_decl)
17899451b44SJordan Rupprecht
17999451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
18099451b44SJordan Rupprecht    def test_printing_struct_with_multiple_locals(self):
18199451b44SJordan Rupprecht        """
18299451b44SJordan Rupprecht        Prints a local variable and checks that we don't load other local
18399451b44SJordan Rupprecht        variables.
18499451b44SJordan Rupprecht        """
18599451b44SJordan Rupprecht        self.clean_setup(location="multiple locals function")
18699451b44SJordan Rupprecht
187*2238dcc3SJonas Devlieghere        self.expect("expr struct_var", substrs=["(SomeStruct) $0"])
18899451b44SJordan Rupprecht
18999451b44SJordan Rupprecht        # We loaded SomeStruct and its member types for printing.
19099451b44SJordan Rupprecht        self.assert_decl_loaded(self.some_struct_decl)
19199451b44SJordan Rupprecht        self.assert_decl_loaded(self.struct_behind_ptr_decl)
19299451b44SJordan Rupprecht        self.assert_decl_loaded(self.struct_behind_ref_decl)
19399451b44SJordan Rupprecht
19499451b44SJordan Rupprecht        # FIXME: We don't use these variables, but we seem to load all local
19599451b44SJordan Rupprecht        # local variables.
19699451b44SJordan Rupprecht        self.assert_decl_not_completed(self.other_struct_decl)
19799451b44SJordan Rupprecht        self.assert_decl_not_completed(self.class_in_namespace_decl)
19899451b44SJordan Rupprecht
19999451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
20099451b44SJordan Rupprecht    def test_addr_of_struct(self):
20199451b44SJordan Rupprecht        """
20299451b44SJordan Rupprecht        Prints the address of a local variable (which is a struct).
20399451b44SJordan Rupprecht        """
20499451b44SJordan Rupprecht        self.clean_setup(location="multiple locals function")
20599451b44SJordan Rupprecht
206*2238dcc3SJonas Devlieghere        self.expect("expr &struct_var", substrs=["(SomeStruct *) $0"])
20799451b44SJordan Rupprecht
20899451b44SJordan Rupprecht        # We loaded SomeStruct.
20999451b44SJordan Rupprecht        self.assert_decl_loaded(self.some_struct_decl)
21099451b44SJordan Rupprecht
21199451b44SJordan Rupprecht        # The member declarations should not be completed.
21299451b44SJordan Rupprecht        self.assert_decl_not_completed(self.struct_behind_ptr_decl)
21399451b44SJordan Rupprecht        self.assert_decl_not_completed(self.struct_behind_ref_decl)
21499451b44SJordan Rupprecht
21599451b44SJordan Rupprecht        # FIXME: The first member was behind a pointer so it shouldn't be
21699451b44SJordan Rupprecht        # completed. Somehow LLDB really wants to load the first member, so
21799451b44SJordan Rupprecht        # that is why have it defined here.
21899451b44SJordan Rupprecht        self.assert_decl_loaded(self.struct_first_member_decl)
21999451b44SJordan Rupprecht
22099451b44SJordan Rupprecht        # FIXME: We don't use these variables, but we seem to load all local
22199451b44SJordan Rupprecht        # local variables.
22299451b44SJordan Rupprecht        self.assert_decl_not_completed(self.other_struct_decl)
22399451b44SJordan Rupprecht        self.assert_decl_not_completed(self.class_in_namespace_decl)
22499451b44SJordan Rupprecht
22599451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
22699451b44SJordan Rupprecht    def test_class_function_access_member(self):
22799451b44SJordan Rupprecht        self.clean_setup(location="class function")
22899451b44SJordan Rupprecht
229*2238dcc3SJonas Devlieghere        self.expect("expr member", substrs=["(ClassMember) $0"])
23099451b44SJordan Rupprecht
23199451b44SJordan Rupprecht        # We loaded the current class we touched.
23299451b44SJordan Rupprecht        self.assert_decl_loaded(self.class_we_enter_decl)
23399451b44SJordan Rupprecht        # We loaded the unused members of this class.
23499451b44SJordan Rupprecht        self.assert_decl_loaded(self.unused_class_member_decl)
23599451b44SJordan Rupprecht        self.assert_decl_not_completed(self.unused_class_member_ptr_decl)
23699451b44SJordan Rupprecht        # We loaded the member we used.
23799451b44SJordan Rupprecht        self.assert_decl_loaded(self.class_member_decl)
23834c697c8SRaphael Isemann        # We didn't load the type of the unused static member.
23934c697c8SRaphael Isemann        self.assert_decl_not_completed(self.class_static_member_decl)
24099451b44SJordan Rupprecht
24199451b44SJordan Rupprecht        # This should not have loaded anything else.
24299451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.other_struct_decl)
24399451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.some_struct_decl)
24499451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.class_in_namespace_decl)
245