Files
clang-p2996/lldb/test/API/python_api/expression_path/TestExpressionPath.py
Tonko Sabolčec 14642dc740 [lldb] Fix member access in GetExpressionPath
This change fixes two issues in ValueObject::GetExpressionPath method:

 1. Accessing members of struct references used to produce expression
    paths such as "str.&str.member" (instead of the expected
    "str.member"). This is fixed by assigning the flag tha the child
    value is a dereference when calling Dereference() on references
    and adjusting logic in expression path creation.

 2. If the parent of member access is dereference, the produced
    expression path was "*(ptr).member". This is incorrect, since it
    dereferences the member instead of the pointer. This is fixed by
    wrapping dereference expression into parenthesis, resulting with
    "(*(ptr)).member".

Reviewed By: werat, clayborg

Differential Revision: https://reviews.llvm.org/D132734
2022-09-30 11:25:07 +00:00

119 lines
5.5 KiB
Python

"""Test that SBFrame::GetExpressionPath construct valid expressions"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class SBValueGetExpressionPathTest(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def path(self, value):
"""Constructs the expression path given the SBValue"""
if not value:
return None
stream = lldb.SBStream()
if not value.GetExpressionPath(stream):
return None
return stream.GetData()
def test_expression_path(self):
"""Test that SBFrame::GetExpressionPath construct valid expressions"""
self.build()
self.setTearDownCleanup()
exe = self.getBuildArtifact("a.out")
# Create the target
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
# Set the breakpoints
breakpoint = target.BreakpointCreateBySourceRegex(
'Set breakpoint here', lldb.SBFileSpec("main.cpp"))
self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)
# Launch the process, and do not stop at the entry point.
process = target.LaunchSimple(
None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
# Frame #0 should be at our breakpoint.
threads = lldbutil.get_threads_stopped_at_breakpoint(
process, breakpoint)
self.assertEquals(len(threads), 1)
self.thread = threads[0]
self.frame = self.thread.frames[0]
self.assertTrue(self.frame, "Frame 0 is valid.")
# Find "b" variables in frame
b = self.frame.FindVariable("b")
bp = self.frame.FindVariable("b_ptr")
br = self.frame.FindVariable("b_ref")
bpr = self.frame.FindVariable("b_ptr_ref")
# Check expression paths
self.assertEqual(self.path(b), "b")
self.assertEqual(self.path(bp), "b_ptr")
self.assertEqual(self.path(br), "b_ref")
self.assertEqual(self.path(bpr), "b_ptr_ref")
# Dereference "b" pointers
bp_deref = bp.Dereference()
bpr_deref = bpr.Dereference() # a pointer
bpr_deref2 = bpr_deref.Dereference() # two Dereference() calls to get object
# Check expression paths
self.assertEqual(self.path(bp_deref), "*(b_ptr)")
self.assertEqual(self.path(bpr_deref), "b_ptr_ref")
self.assertEqual(self.path(bpr_deref2), "*(b_ptr_ref)")
# Access "b" members and check expression paths
self.assertEqual(self.path(b.GetChildMemberWithName("x")), "b.x")
self.assertEqual(self.path(bp.GetChildMemberWithName("x")), "b_ptr->x")
self.assertEqual(self.path(br.GetChildMemberWithName("x")), "b_ref.x")
self.assertEqual(self.path(bp_deref.GetChildMemberWithName("x")), "(*(b_ptr)).x")
self.assertEqual(self.path(bpr_deref.GetChildMemberWithName("x")), "b_ptr_ref->x")
self.assertEqual(self.path(bpr_deref2.GetChildMemberWithName("x")), "(*(b_ptr_ref)).x")
# TODO: Uncomment once accessing members on pointer references is supported.
# self.assertEqual(self.path(bpr.GetChildMemberWithName("x")), "b_ptr_ref->x")
# Try few expressions with multiple member access
bp_ar_x = bp.GetChildMemberWithName("a_ref").GetChildMemberWithName("x")
br_ar_y = br.GetChildMemberWithName("a_ref").GetChildMemberWithName("y")
self.assertEqual(self.path(bp_ar_x), "b_ptr->a_ref.x")
self.assertEqual(self.path(br_ar_y), "b_ref.a_ref.y")
bpr_deref_apr_deref = bpr_deref.GetChildMemberWithName("a_ptr_ref").Dereference()
bpr_deref_apr_deref2 = bpr_deref_apr_deref.Dereference()
self.assertEqual(self.path(bpr_deref_apr_deref), "b_ptr_ref->a_ptr_ref")
self.assertEqual(self.path(bpr_deref_apr_deref2), "*(b_ptr_ref->a_ptr_ref)")
bpr_deref_apr_deref_x = bpr_deref_apr_deref.GetChildMemberWithName("x")
bpr_deref_apr_deref2_x = bpr_deref_apr_deref2.GetChildMemberWithName("x")
self.assertEqual(self.path(bpr_deref_apr_deref_x), "b_ptr_ref->a_ptr_ref->x")
self.assertEqual(self.path(bpr_deref_apr_deref2_x), "(*(b_ptr_ref->a_ptr_ref)).x")
# Find "c" variables in frame
c = self.frame.FindVariable("c")
cp = self.frame.FindVariable("c_ptr")
cr = self.frame.FindVariable("c_ref")
cpr = self.frame.FindVariable("c_ptr_ref")
# Dereference pointers
cp_deref = cp.Dereference()
cpr_deref = cpr.Dereference() # a pointer
cpr_deref2 = cpr_deref.Dereference() # two Dereference() calls to get object
# Check expression paths
self.assertEqual(self.path(cp_deref), "*(c_ptr)")
self.assertEqual(self.path(cpr_deref), "c_ptr_ref")
self.assertEqual(self.path(cpr_deref2), "*(c_ptr_ref)")
# Access members on "c" variables and check expression paths
self.assertEqual(self.path(c.GetChildMemberWithName("x")), "c.x")
self.assertEqual(self.path(cp.GetChildMemberWithName("x")), "c_ptr->x")
self.assertEqual(self.path(cr.GetChildMemberWithName("x")), "c_ref.x")
self.assertEqual(self.path(cp_deref.GetChildMemberWithName("x")), "(*(c_ptr)).x")
self.assertEqual(self.path(cpr_deref.GetChildMemberWithName("x")), "c_ptr_ref->x")
self.assertEqual(self.path(cpr_deref2.GetChildMemberWithName("x")), "(*(c_ptr_ref)).x")
# TODO: Uncomment once accessing members on pointer references is supported.
# self.assertEqual(self.path(cpr.GetChildMemberWithName("x")), "c_ptr_ref->x")