| """ |
| 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() |