""" This tests LLDB's ability to merge structs into the shared per-target Clang ASTContext. This just focuses on indirect imports (i.e., a declaration gets imported from the lldb::Module AST into the expression AST and then the declaration gets imported to the scratch AST because it is part of the ValueObject type of the result) and direct imports (i.e., a declaration gets directly imported from a lldb::Module AST to the scratch AST, e.g., via 'frame var'). """ import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil class TestCase(TestBase): def common_setup(self): self.build() lldbutil.run_to_source_breakpoint( self, "// break here", lldb.SBFileSpec("main.cpp") ) def do_pass(self, kind, var, expected_type, expected_children): if kind == "expression": self.expect_expr( var, result_type=expected_type, result_children=expected_children ) elif kind == "path": self.expect_var_path(var, type=expected_type, children=expected_children) else: self.fail("Unknown var evaluation kind: " + var) def pull_in_and_merge(self, var, type, children): """ Pulls in the specified variable into the scratch AST. Afterwards tries merging the declaration. The method of pulling the declaration into the scratch AST is defined by the first_pass/second_pass instance variables. """ # This pulls in the declaration into the scratch AST. self.do_pass(self.first_pass, var, type, children) # This pulls in the declaration a second time and forces us to merge with # the existing declaration (or reuse the existing declaration). self.do_pass(self.second_pass, var, type, children) def do_tests(self): """Just forwards all the variables/types/childrens to pull_in_and_merge.""" self.pull_in_and_merge( "decl_in_func", type="DeclInFunc", children=[ValueCheck(name="member")] ) self.pull_in_and_merge( "top_level_struct", type="TopLevelStruct", children=[ValueCheck(name="member")], ) self.pull_in_and_merge( "inner_struct", type="OuterStruct::InnerStruct", children=[ValueCheck(name="member")], ) self.pull_in_and_merge( "typedef_struct", type="TypedefStruct", children=[ValueCheck(name="member")], ) self.pull_in_and_merge( "namespace_struct", type="NS::NamespaceStruct", children=[ValueCheck(name="member")], ) self.pull_in_and_merge( "unnamed_namespace_struct", type="UnnamedNamespaceStruct", children=[ValueCheck(name="member")], ) self.pull_in_and_merge( "extern_c_struct", type="ExternCStruct", children=[ValueCheck(name="member")], ) @no_debug_info_test def test_direct_and_indirect(self): """ First variable paths pull in a declaration directly. Then the expression evaluator pulls the declaration in indirectly. """ self.common_setup() self.first_pass = "path" self.second_pass = "expression" self.do_tests() @no_debug_info_test def test_indirect_and_indirect(self): """ The expression evaluator pulls in the declaration indirectly and then repeat that process. """ self.common_setup() self.first_pass = "expression" self.second_pass = "expression" self.do_tests() @no_debug_info_test def test_indirect_and_direct(self): """ The expression evaluator pulls in the declaration indirectly and then variable paths pull it in directly. """ self.common_setup() self.first_pass = "expression" self.second_pass = "path" self.do_tests() @no_debug_info_test def test_direct_and_direct(self): """ Variable paths pulls in the declaration indirectly and then repeat that process. """ self.common_setup() self.first_pass = "path" self.second_pass = "path" self.do_tests()