1from lldbsuite.test.decorators import * 2from lldbsuite.test.lldbtest import * 3from lldbsuite.test import lldbutil 4 5""" 6This test ensures that we only create Clang AST nodes in our module AST 7when 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 previous 12 step. 13""" 14 15 16class TestCase(TestBase): 17 NO_DEBUG_INFO_TESTCASE = True 18 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 model 27 # structs in Clang. 28 struct_decl_kind = "CXXRecordDecl" 29 30 # The decls we use in this program in the format that 31 # decl_in_line and decl_completed_in_line expect (which is a pair of 32 # 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 loaded 49 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 of 78 # the line. 79 decl_name = " " + decl[1] + " " 80 decl_name_eol = " " + decl[1] + "\n" 81 if not decl_kind in line: 82 return False 83 return decl_name in line or decl_name_eol in line 84 85 def decl_completed_in_line(self, line, decl): 86 """ 87 Returns true iff the given line declares the given Clang decl and 88 the decl was completed (i.e., it has no undeserialized declarations 89 in it). 90 """ 91 return ( 92 self.decl_in_line(line, decl) 93 and not "<undeserialized declarations>" in line 94 ) 95 96 # The following asserts are used for checking if certain Clang declarations 97 # 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 not 103 loaded. If this assert fails it is usually fine to turn it into a 104 assert_decl_not_loaded or assert_decl_not_completed assuming LLDB's 105 functionality has not suffered by not loading this declaration. 106 """ 107 ast = self.get_ast_dump() 108 found = False 109 for line in ast.splitlines(): 110 if self.decl_in_line(line, decl): 111 found = True 112 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" + ast 118 ) 119 120 def assert_decl_not_completed(self, decl): 121 """ 122 Asserts that the given decl is currently not completed in the module's 123 AST. It may be loaded but then can can only contain undeserialized 124 declarations. 125 """ 126 ast = self.get_ast_dump() 127 found = False 128 for line in ast.splitlines(): 129 error_msg = "Unexpected completed decl: '" + line + "'.\nAST:\n" + ast 130 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's 135 AST. 136 """ 137 ast = self.get_ast_dump() 138 found = False 139 for line in ast.splitlines(): 140 error_msg = "Unexpected loaded decl: '" + line + "'\nAST:\n" + ast 141 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 string 146 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 local 183 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 local 195 # 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 be 216 # completed. Somehow LLDB really wants to load the first member, so 217 # 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 local 221 # 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