brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.8 KiB · 032ed41 Raw
245 lines · python
1from lldbsuite.test.decorators import *2from lldbsuite.test.lldbtest import *3from lldbsuite.test import lldbutil4 5"""6This test ensures that we only create Clang AST nodes in our module AST7when we actually need them.8 9All tests in this file behave like this:10  1. Use LLDB to do something (expression evaluation, breakpoint setting, etc.).11  2. Check that certain Clang AST nodes were not loaded during the previous12     step.13"""14 15 16class TestCase(TestBase):17    NO_DEBUG_INFO_TESTCASE = True18 19    def setUp(self):20        TestBase.setUp(self)21        # Only build this test once.22        self.build()23 24    # Clang declaration kind we are looking for.25    class_decl_kind = "CXXRecordDecl"26    # FIXME: This shouldn't be a CXXRecordDecl, but that's how we model27    # structs in Clang.28    struct_decl_kind = "CXXRecordDecl"29 30    # The decls we use in this program in the format that31    # decl_in_line and decl_completed_in_line expect (which is a pair of32    # node type and the unqualified declaration name.33    struct_first_member_decl = [struct_decl_kind, "StructFirstMember"]34    struct_behind_ptr_decl = [struct_decl_kind, "StructBehindPointer"]35    struct_behind_ref_decl = [struct_decl_kind, "StructBehindRef"]36    struct_member_decl = [struct_decl_kind, "StructMember"]37    some_struct_decl = [struct_decl_kind, "SomeStruct"]38    other_struct_decl = [struct_decl_kind, "OtherStruct"]39    class_in_namespace_decl = [class_decl_kind, "ClassInNamespace"]40    class_we_enter_decl = [class_decl_kind, "ClassWeEnter"]41    class_member_decl = [struct_decl_kind, "ClassMember"]42    class_static_member_decl = [struct_decl_kind, "StaticClassMember"]43    unused_class_member_decl = [struct_decl_kind, "UnusedClassMember"]44    unused_class_member_ptr_decl = [struct_decl_kind, "UnusedClassMemberPtr"]45 46    def assert_no_decls_loaded(self):47        """48        Asserts that no known declarations in this test are loaded49        into the module's AST.50        """51        self.assert_decl_not_loaded(self.struct_first_member_decl)52        self.assert_decl_not_loaded(self.struct_behind_ptr_decl)53        self.assert_decl_not_loaded(self.struct_behind_ref_decl)54        self.assert_decl_not_loaded(self.struct_member_decl)55        self.assert_decl_not_loaded(self.some_struct_decl)56        self.assert_decl_not_loaded(self.other_struct_decl)57        self.assert_decl_not_loaded(self.class_in_namespace_decl)58        self.assert_decl_not_loaded(self.class_member_decl)59        self.assert_decl_not_loaded(self.class_static_member_decl)60        self.assert_decl_not_loaded(self.unused_class_member_decl)61 62    def get_ast_dump(self):63        """Returns the dumped Clang AST of the module as a string"""64        res = lldb.SBCommandReturnObject()65        ci = self.dbg.GetCommandInterpreter()66        ci.HandleCommand("target modules dump ast a.out", res)67        self.assertTrue(res.Succeeded())68        return res.GetOutput()69 70    def decl_in_line(self, line, decl):71        """72        Returns true iff the given line declares the given Clang decl.73        The line is expected to be in the form of Clang's AST dump.74        """75        line = line.rstrip() + "\n"76        decl_kind = "-" + decl[0] + " "77        # Either the decl is somewhere in the line or at the end of78        # the line.79        decl_name = " " + decl[1] + " "80        decl_name_eol = " " + decl[1] + "\n"81        if not decl_kind in line:82            return False83        return decl_name in line or decl_name_eol in line84 85    def decl_completed_in_line(self, line, decl):86        """87        Returns true iff the given line declares the given Clang decl and88        the decl was completed (i.e., it has no undeserialized declarations89        in it).90        """91        return (92            self.decl_in_line(line, decl)93            and not "<undeserialized declarations>" in line94        )95 96    # The following asserts are used for checking if certain Clang declarations97    # were loaded or not since the target was created.98 99    def assert_decl_loaded(self, decl):100        """101        Asserts the given decl is currently loaded.102        Note: This test is about checking that types/declarations are not103        loaded. If this assert fails it is usually fine to turn it into a104        assert_decl_not_loaded or assert_decl_not_completed assuming LLDB's105        functionality has not suffered by not loading this declaration.106        """107        ast = self.get_ast_dump()108        found = False109        for line in ast.splitlines():110            if self.decl_in_line(line, decl):111                found = True112                self.assertTrue(113                    self.decl_completed_in_line(line, decl),114                    "Should have called assert_decl_not_completed",115                )116        self.assertTrue(117            found, "Declaration no longer loaded " + str(decl) + ".\nAST:\n" + ast118        )119 120    def assert_decl_not_completed(self, decl):121        """122        Asserts that the given decl is currently not completed in the module's123        AST. It may be loaded but then can can only contain undeserialized124        declarations.125        """126        ast = self.get_ast_dump()127        found = False128        for line in ast.splitlines():129            error_msg = "Unexpected completed decl: '" + line + "'.\nAST:\n" + ast130            self.assertFalse(self.decl_completed_in_line(line, decl), error_msg)131 132    def assert_decl_not_loaded(self, decl):133        """134        Asserts that the given decl is currently not loaded in the module's135        AST.136        """137        ast = self.get_ast_dump()138        found = False139        for line in ast.splitlines():140            error_msg = "Unexpected loaded decl: '" + line + "'\nAST:\n" + ast141            self.assertFalse(self.decl_in_line(line, decl), error_msg)142 143    def clean_setup(self, location):144        """145        Runs to the line with the source line with the given location string146        and ensures that our module AST is empty.147        """148        lldbutil.run_to_source_breakpoint(149            self, "// Location: " + location, lldb.SBFileSpec("main.cpp")150        )151        # Make sure no declarations are loaded initially.152        self.assert_no_decls_loaded()153 154    @add_test_categories(["dwarf"])155    def test_arithmetic_expression_in_main(self):156        """Runs a simple arithmetic expression which should load nothing."""157        self.clean_setup(location="multiple locals function")158 159        self.expect("expr 1 + (int)2.0", substrs=["(int) $0"])160 161        # This should not have loaded any decls.162        self.assert_no_decls_loaded()163 164    @add_test_categories(["dwarf"])165    def test_printing_local_variable_in_other_struct_func(self):166        """167        Prints a local variable and makes sure no unrelated types are loaded.168        """169        self.clean_setup(location="other struct function")170 171        self.expect("expr other_struct_var", substrs=["(OtherStruct) $0"])172        # The decl we run on was loaded.173        self.assert_decl_loaded(self.other_struct_decl)174 175        # This should not have loaded anything else.176        self.assert_decl_not_loaded(self.some_struct_decl)177        self.assert_decl_not_loaded(self.class_in_namespace_decl)178 179    @add_test_categories(["dwarf"])180    def test_printing_struct_with_multiple_locals(self):181        """182        Prints a local variable and checks that we don't load other local183        variables.184        """185        self.clean_setup(location="multiple locals function")186 187        self.expect("expr struct_var", substrs=["(SomeStruct) $0"])188 189        # We loaded SomeStruct and its member types for printing.190        self.assert_decl_loaded(self.some_struct_decl)191        self.assert_decl_loaded(self.struct_behind_ptr_decl)192        self.assert_decl_loaded(self.struct_behind_ref_decl)193 194        # FIXME: We don't use these variables, but we seem to load all local195        # local variables.196        self.assert_decl_not_completed(self.other_struct_decl)197        self.assert_decl_not_completed(self.class_in_namespace_decl)198 199    @add_test_categories(["dwarf"])200    def test_addr_of_struct(self):201        """202        Prints the address of a local variable (which is a struct).203        """204        self.clean_setup(location="multiple locals function")205 206        self.expect("expr &struct_var", substrs=["(SomeStruct *) $0"])207 208        # We loaded SomeStruct.209        self.assert_decl_loaded(self.some_struct_decl)210 211        # The member declarations should not be completed.212        self.assert_decl_not_completed(self.struct_behind_ptr_decl)213        self.assert_decl_not_completed(self.struct_behind_ref_decl)214 215        # FIXME: The first member was behind a pointer so it shouldn't be216        # completed. Somehow LLDB really wants to load the first member, so217        # that is why have it defined here.218        self.assert_decl_loaded(self.struct_first_member_decl)219 220        # FIXME: We don't use these variables, but we seem to load all local221        # local variables.222        self.assert_decl_not_completed(self.other_struct_decl)223        self.assert_decl_not_completed(self.class_in_namespace_decl)224 225    @add_test_categories(["dwarf"])226    def test_class_function_access_member(self):227        self.clean_setup(location="class function")228 229        self.expect("expr member", substrs=["(ClassMember) $0"])230 231        # We loaded the current class we touched.232        self.assert_decl_loaded(self.class_we_enter_decl)233        # We loaded the unused members of this class.234        self.assert_decl_loaded(self.unused_class_member_decl)235        self.assert_decl_not_completed(self.unused_class_member_ptr_decl)236        # We loaded the member we used.237        self.assert_decl_loaded(self.class_member_decl)238        # We didn't load the type of the unused static member.239        self.assert_decl_not_completed(self.class_static_member_decl)240 241        # This should not have loaded anything else.242        self.assert_decl_not_loaded(self.other_struct_decl)243        self.assert_decl_not_loaded(self.some_struct_decl)244        self.assert_decl_not_loaded(self.class_in_namespace_decl)245