xref: /llvm-project/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py (revision 2aed0d9cd3fc8f3c600d59b8b10d10a4466e50c6)
17e16571eSAdrian Vogelsgesangimport lldb
27e16571eSAdrian Vogelsgesangfrom lldbsuite.test.decorators import *
37e16571eSAdrian Vogelsgesangfrom lldbsuite.test.lldbtest import *
47e16571eSAdrian Vogelsgesangfrom lldbsuite.test import lldbutil
57e16571eSAdrian Vogelsgesang
6*2aed0d9cSAdrian Vogelsgesangimport re
77e16571eSAdrian Vogelsgesang
87e16571eSAdrian Vogelsgesangclass LibCxxInternalsRecognizerTestCase(TestBase):
97e16571eSAdrian Vogelsgesang    NO_DEBUG_INFO_TESTCASE = True
107e16571eSAdrian Vogelsgesang
117e16571eSAdrian Vogelsgesang    @add_test_categories(["libc++"])
12*2aed0d9cSAdrian Vogelsgesang    @skipIf(compiler="clang", compiler_version=["<", "16.0"])
137e16571eSAdrian Vogelsgesang    def test_frame_recognizer(self):
147e16571eSAdrian Vogelsgesang        """Test that implementation details of libc++ are hidden"""
157e16571eSAdrian Vogelsgesang        self.build()
167e16571eSAdrian Vogelsgesang        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
177e16571eSAdrian Vogelsgesang            self, "break here", lldb.SBFileSpec("main.cpp")
187e16571eSAdrian Vogelsgesang        )
197e16571eSAdrian Vogelsgesang
207e16571eSAdrian Vogelsgesang        expected_parents = {
217e16571eSAdrian Vogelsgesang            "sort_less(int, int)": ["::sort", "test_algorithms"],
227e16571eSAdrian Vogelsgesang            # `std::ranges::sort` is implemented as an object of types `__sort`.
237e16571eSAdrian Vogelsgesang            # We never hide the frame of the entry-point into the standard library, even
247e16571eSAdrian Vogelsgesang            # if the name starts with `__` which usually indicates an internal function.
257e16571eSAdrian Vogelsgesang            "ranges_sort_less(int, int)": [
26*2aed0d9cSAdrian Vogelsgesang                re.compile("ranges::__sort::(__fn::)?operator\(\)"),
277e16571eSAdrian Vogelsgesang                "test_algorithms",
287e16571eSAdrian Vogelsgesang            ],
297e16571eSAdrian Vogelsgesang            # `ranges::views::transform` internally uses `std::invoke`, and that
307e16571eSAdrian Vogelsgesang            # call also shows up in the stack trace
317e16571eSAdrian Vogelsgesang            "view_transform(int)": [
327e16571eSAdrian Vogelsgesang                "::invoke",
337e16571eSAdrian Vogelsgesang                "ranges::transform_view",
347e16571eSAdrian Vogelsgesang                "test_algorithms",
357e16571eSAdrian Vogelsgesang            ],
367e16571eSAdrian Vogelsgesang            # Various types of `invoke` calls
377e16571eSAdrian Vogelsgesang            "consume_number(int)": ["::invoke", "test_invoke"],
387e16571eSAdrian Vogelsgesang            "invoke_add(int, int)": ["::invoke", "test_invoke"],
397e16571eSAdrian Vogelsgesang            "Callable::member_function(int) const": ["::invoke", "test_invoke"],
407e16571eSAdrian Vogelsgesang            "Callable::operator()(int) const": ["::invoke", "test_invoke"],
417e16571eSAdrian Vogelsgesang            # Containers
427e16571eSAdrian Vogelsgesang            "MyKey::operator<(MyKey const&) const": [
437e16571eSAdrian Vogelsgesang                "less",
447e16571eSAdrian Vogelsgesang                "::emplace",
457e16571eSAdrian Vogelsgesang                "test_containers",
467e16571eSAdrian Vogelsgesang            ],
477e16571eSAdrian Vogelsgesang        }
487e16571eSAdrian Vogelsgesang        stop_set = set()
497e16571eSAdrian Vogelsgesang        while process.GetState() != lldb.eStateExited:
507e16571eSAdrian Vogelsgesang            fn = thread.GetFrameAtIndex(0).GetFunctionName()
517e16571eSAdrian Vogelsgesang            stop_set.add(fn)
527e16571eSAdrian Vogelsgesang            self.assertIn(fn, expected_parents.keys())
537e16571eSAdrian Vogelsgesang            frame_id = 1
547e16571eSAdrian Vogelsgesang            for expected_parent in expected_parents[fn]:
557e16571eSAdrian Vogelsgesang                # Skip all hidden frames
567e16571eSAdrian Vogelsgesang                while (
577e16571eSAdrian Vogelsgesang                    frame_id < thread.GetNumFrames()
587e16571eSAdrian Vogelsgesang                    and thread.GetFrameAtIndex(frame_id).IsHidden()
597e16571eSAdrian Vogelsgesang                ):
607e16571eSAdrian Vogelsgesang                    frame_id = frame_id + 1
617e16571eSAdrian Vogelsgesang                # Expect the correct parent frame
62*2aed0d9cSAdrian Vogelsgesang                func_name = thread.GetFrameAtIndex(frame_id).GetFunctionName()
63*2aed0d9cSAdrian Vogelsgesang                if isinstance(expected_parent, re.Pattern):
64*2aed0d9cSAdrian Vogelsgesang                    self.assertTrue(
65*2aed0d9cSAdrian Vogelsgesang                        expected_parent.search(func_name) is not None,
66*2aed0d9cSAdrian Vogelsgesang                        f"'{expected_parent}' not found in '{func_name}'"
677e16571eSAdrian Vogelsgesang                    )
68*2aed0d9cSAdrian Vogelsgesang                else:
69*2aed0d9cSAdrian Vogelsgesang                    self.assertIn(expected_parent, func_name)
707e16571eSAdrian Vogelsgesang                frame_id = frame_id + 1
717e16571eSAdrian Vogelsgesang            process.Continue()
727e16571eSAdrian Vogelsgesang
737e16571eSAdrian Vogelsgesang        # Make sure that we actually verified all intended scenarios
747e16571eSAdrian Vogelsgesang        self.assertEqual(len(stop_set), len(expected_parents))
75