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 Rupprechtclass TestCase(TestBase):
1699451b44SJordan Rupprecht
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"]
42*34c697c8SRaphael 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)
59*34c697c8SRaphael 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()
6699451b44SJordan Rupprecht        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        """
9199451b44SJordan Rupprecht        return self.decl_in_line(line, decl) and not "<undeserialized declarations>" in line
9299451b44SJordan Rupprecht
9399451b44SJordan Rupprecht    # The following asserts are used for checking if certain Clang declarations
9499451b44SJordan Rupprecht    # were loaded or not since the target was created.
9599451b44SJordan Rupprecht
9699451b44SJordan Rupprecht    def assert_decl_loaded(self, decl):
9799451b44SJordan Rupprecht        """
9899451b44SJordan Rupprecht        Asserts the given decl is currently loaded.
9999451b44SJordan Rupprecht        Note: This test is about checking that types/declarations are not
10099451b44SJordan Rupprecht        loaded. If this assert fails it is usually fine to turn it into a
10199451b44SJordan Rupprecht        assert_decl_not_loaded or assert_decl_not_completed assuming LLDB's
10299451b44SJordan Rupprecht        functionality has not suffered by not loading this declaration.
10399451b44SJordan Rupprecht        """
10499451b44SJordan Rupprecht        ast = self.get_ast_dump()
10599451b44SJordan Rupprecht        found = False
10699451b44SJordan Rupprecht        for line in ast.splitlines():
10799451b44SJordan Rupprecht          if self.decl_in_line(line, decl):
10899451b44SJordan Rupprecht            found = True
10999451b44SJordan Rupprecht            self.assertTrue(self.decl_completed_in_line(line, decl),
11099451b44SJordan Rupprecht                            "Should have called assert_decl_not_completed")
11199451b44SJordan Rupprecht        self.assertTrue(found, "Declaration no longer loaded " + str(decl) +
11299451b44SJordan Rupprecht            ".\nAST:\n" + ast)
11399451b44SJordan Rupprecht
11499451b44SJordan Rupprecht    def assert_decl_not_completed(self, decl):
11599451b44SJordan Rupprecht        """
11699451b44SJordan Rupprecht        Asserts that the given decl is currently not completed in the module's
11799451b44SJordan Rupprecht        AST. It may be loaded but then can can only contain undeserialized
11899451b44SJordan Rupprecht        declarations.
11999451b44SJordan Rupprecht        """
12099451b44SJordan Rupprecht        ast = self.get_ast_dump()
12199451b44SJordan Rupprecht        found = False
12299451b44SJordan Rupprecht        for line in ast.splitlines():
12399451b44SJordan Rupprecht          error_msg = "Unexpected completed decl: '" + line + "'.\nAST:\n" + ast
12499451b44SJordan Rupprecht          self.assertFalse(self.decl_completed_in_line(line, decl), error_msg)
12599451b44SJordan Rupprecht
12699451b44SJordan Rupprecht    def assert_decl_not_loaded(self, decl):
12799451b44SJordan Rupprecht        """
12899451b44SJordan Rupprecht        Asserts that the given decl is currently not loaded in the module's
12999451b44SJordan Rupprecht        AST.
13099451b44SJordan Rupprecht        """
13199451b44SJordan Rupprecht        ast = self.get_ast_dump()
13299451b44SJordan Rupprecht        found = False
13399451b44SJordan Rupprecht        for line in ast.splitlines():
13499451b44SJordan Rupprecht          error_msg = "Unexpected loaded decl: '" + line + "'\nAST:\n" + ast
13599451b44SJordan Rupprecht          self.assertFalse(self.decl_in_line(line, decl), error_msg)
13699451b44SJordan Rupprecht
13799451b44SJordan Rupprecht
13899451b44SJordan Rupprecht    def clean_setup(self, location):
13999451b44SJordan Rupprecht        """
14099451b44SJordan Rupprecht        Runs to the line with the source line with the given location string
14199451b44SJordan Rupprecht        and ensures that our module AST is empty.
14299451b44SJordan Rupprecht        """
14399451b44SJordan Rupprecht        lldbutil.run_to_source_breakpoint(self,
14499451b44SJordan Rupprecht            "// Location: " + location, lldb.SBFileSpec("main.cpp"))
14599451b44SJordan Rupprecht        # Make sure no declarations are loaded initially.
14699451b44SJordan Rupprecht        self.assert_no_decls_loaded()
14799451b44SJordan Rupprecht
14899451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
14999451b44SJordan Rupprecht    def test_arithmetic_expression_in_main(self):
15099451b44SJordan Rupprecht        """ Runs a simple arithmetic expression which should load nothing. """
15199451b44SJordan Rupprecht        self.clean_setup(location="multiple locals function")
15299451b44SJordan Rupprecht
15399451b44SJordan Rupprecht        self.expect("expr 1 + (int)2.0", substrs=['(int) $0'])
15499451b44SJordan Rupprecht
15599451b44SJordan Rupprecht        # This should not have loaded any decls.
15699451b44SJordan Rupprecht        self.assert_no_decls_loaded()
15799451b44SJordan Rupprecht
15899451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
15999451b44SJordan Rupprecht    def test_printing_local_variable_in_other_struct_func(self):
16099451b44SJordan Rupprecht        """
16199451b44SJordan Rupprecht        Prints a local variable and makes sure no unrelated types are loaded.
16299451b44SJordan Rupprecht        """
16399451b44SJordan Rupprecht        self.clean_setup(location="other struct function")
16499451b44SJordan Rupprecht
16599451b44SJordan Rupprecht        self.expect("expr other_struct_var", substrs=['(OtherStruct) $0'])
16699451b44SJordan Rupprecht        # The decl we run on was loaded.
16799451b44SJordan Rupprecht        self.assert_decl_loaded(self.other_struct_decl)
16899451b44SJordan Rupprecht
16999451b44SJordan Rupprecht        # This should not have loaded anything else.
17099451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.some_struct_decl)
17199451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.class_in_namespace_decl)
17299451b44SJordan Rupprecht
17399451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
17499451b44SJordan Rupprecht    def test_printing_struct_with_multiple_locals(self):
17599451b44SJordan Rupprecht        """
17699451b44SJordan Rupprecht        Prints a local variable and checks that we don't load other local
17799451b44SJordan Rupprecht        variables.
17899451b44SJordan Rupprecht        """
17999451b44SJordan Rupprecht        self.clean_setup(location="multiple locals function")
18099451b44SJordan Rupprecht
18199451b44SJordan Rupprecht        self.expect("expr struct_var", substrs=['(SomeStruct) $0'])
18299451b44SJordan Rupprecht
18399451b44SJordan Rupprecht        # We loaded SomeStruct and its member types for printing.
18499451b44SJordan Rupprecht        self.assert_decl_loaded(self.some_struct_decl)
18599451b44SJordan Rupprecht        self.assert_decl_loaded(self.struct_behind_ptr_decl)
18699451b44SJordan Rupprecht        self.assert_decl_loaded(self.struct_behind_ref_decl)
18799451b44SJordan Rupprecht
18899451b44SJordan Rupprecht        # FIXME: We don't use these variables, but we seem to load all local
18999451b44SJordan Rupprecht        # local variables.
19099451b44SJordan Rupprecht        self.assert_decl_not_completed(self.other_struct_decl)
19199451b44SJordan Rupprecht        self.assert_decl_not_completed(self.class_in_namespace_decl)
19299451b44SJordan Rupprecht
19399451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
19499451b44SJordan Rupprecht    def test_addr_of_struct(self):
19599451b44SJordan Rupprecht        """
19699451b44SJordan Rupprecht        Prints the address of a local variable (which is a struct).
19799451b44SJordan Rupprecht        """
19899451b44SJordan Rupprecht        self.clean_setup(location="multiple locals function")
19999451b44SJordan Rupprecht
20099451b44SJordan Rupprecht        self.expect("expr &struct_var", substrs=['(SomeStruct *) $0'])
20199451b44SJordan Rupprecht
20299451b44SJordan Rupprecht        # We loaded SomeStruct.
20399451b44SJordan Rupprecht        self.assert_decl_loaded(self.some_struct_decl)
20499451b44SJordan Rupprecht
20599451b44SJordan Rupprecht        # The member declarations should not be completed.
20699451b44SJordan Rupprecht        self.assert_decl_not_completed(self.struct_behind_ptr_decl)
20799451b44SJordan Rupprecht        self.assert_decl_not_completed(self.struct_behind_ref_decl)
20899451b44SJordan Rupprecht
20999451b44SJordan Rupprecht        # FIXME: The first member was behind a pointer so it shouldn't be
21099451b44SJordan Rupprecht        # completed. Somehow LLDB really wants to load the first member, so
21199451b44SJordan Rupprecht        # that is why have it defined here.
21299451b44SJordan Rupprecht        self.assert_decl_loaded(self.struct_first_member_decl)
21399451b44SJordan Rupprecht
21499451b44SJordan Rupprecht        # FIXME: We don't use these variables, but we seem to load all local
21599451b44SJordan Rupprecht        # local variables.
21699451b44SJordan Rupprecht        self.assert_decl_not_completed(self.other_struct_decl)
21799451b44SJordan Rupprecht        self.assert_decl_not_completed(self.class_in_namespace_decl)
21899451b44SJordan Rupprecht
21999451b44SJordan Rupprecht    @add_test_categories(["dwarf"])
22099451b44SJordan Rupprecht    def test_class_function_access_member(self):
22199451b44SJordan Rupprecht        self.clean_setup(location="class function")
22299451b44SJordan Rupprecht
22399451b44SJordan Rupprecht        self.expect("expr member", substrs=['(ClassMember) $0'])
22499451b44SJordan Rupprecht
22599451b44SJordan Rupprecht        # We loaded the current class we touched.
22699451b44SJordan Rupprecht        self.assert_decl_loaded(self.class_we_enter_decl)
22799451b44SJordan Rupprecht        # We loaded the unused members of this class.
22899451b44SJordan Rupprecht        self.assert_decl_loaded(self.unused_class_member_decl)
22999451b44SJordan Rupprecht        self.assert_decl_not_completed(self.unused_class_member_ptr_decl)
23099451b44SJordan Rupprecht        # We loaded the member we used.
23199451b44SJordan Rupprecht        self.assert_decl_loaded(self.class_member_decl)
232*34c697c8SRaphael Isemann        # We didn't load the type of the unused static member.
233*34c697c8SRaphael Isemann        self.assert_decl_not_completed(self.class_static_member_decl)
23499451b44SJordan Rupprecht
23599451b44SJordan Rupprecht        # This should not have loaded anything else.
23699451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.other_struct_decl)
23799451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.some_struct_decl)
23899451b44SJordan Rupprecht        self.assert_decl_not_loaded(self.class_in_namespace_decl)
23999451b44SJordan Rupprecht
240