[Lldb-commits] [lldb] 0478ead - [lldb/DataFormatters] Fix the `$$deference$$` synthetic child
Fred Riss via lldb-commits
lldb-commits at lists.llvm.org
Tue Jan 21 13:37:01 PST 2020
Author: Fred Riss
Date: 2020-01-21T13:35:55-08:00
New Revision: 0478eadf73c191199cba12c85785cfafb8bfa174
URL: https://github.com/llvm/llvm-project/commit/0478eadf73c191199cba12c85785cfafb8bfa174
DIFF: https://github.com/llvm/llvm-project/commit/0478eadf73c191199cba12c85785cfafb8bfa174.diff
LOG: [lldb/DataFormatters] Fix the `$$deference$$` synthetic child
Summary:
The ValueObject code checks for a special `$$dereference$$` synthetic
child to allow formatter providers to implement a natural
dereferencing behavior in `frame variable` for objects like smart
pointers.
This support was broken when used directly throught the Python API and
not trhough `frame variable`. The reason is that
SBFrame.FindVariable() will return by default the synthetic variable
if it exists, while `frame variable` will not do this eagerly. The
code in `ValueObject::Dereference()` accounted for the latter but not
for the former. The fix is trivial. The test change includes
additional covergage for the already-working bahevior as it wasn't
covered by the testsuite before.
This commit also adds a short piece of documentatione explaining that
it is possible (even advisable) to provide this synthetic child
outstide of the range of the normal children.
Reviewers: jingham
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73053
Added:
Modified:
lldb/docs/use/variable.rst
lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py
lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py
lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/main.cpp
lldb/source/Core/ValueObject.cpp
Removed:
################################################################################
diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst
index 13a56637ecea..4e3f25eb6a4a 100644
--- a/lldb/docs/use/variable.rst
+++ b/lldb/docs/use/variable.rst
@@ -846,7 +846,7 @@ adheres to a given interface (the word is italicized because Python has no
explicit notion of interface, by that word we mean a given set of methods must
be implemented by the Python class):
-::
+.. code-block:: python
class SyntheticChildrenProvider:
def __init__(self, valobj, internal_dict):
@@ -885,7 +885,28 @@ returning default no-children responses.
If a synthetic child provider supplies a special child named
``$$dereference$$`` then it will be used when evaluating ``operator *`` and
-``operator ->`` in the frame variable command and related SB API functions.
+``operator ->`` in the frame variable command and related SB API
+functions. It is possible to declare this synthetic child without
+including it in the range of children displayed by LLDB. For example,
+this subset of a synthetic children provider class would allow the
+synthetic value to be dereferenced without actually showing any
+synthtic children in the UI:
+
+.. code-block:: python
+
+ class SyntheticChildrenProvider:
+ [...]
+ def num_children(self):
+ return 0
+ def get_child_index(self, name):
+ if name == '$$dereference$$':
+ return 0
+ return -1
+ def get_child_at_index(self, index):
+ if index == 0:
+ return <valobj resulting from dereference>
+ return None
+
For examples of how synthetic children are created, you are encouraged to look
at examples/synthetic in the LLDB trunk. Please, be aware that the code in
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py
index 5f908f76b0ab..9d4759100ce2 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py
@@ -38,19 +38,9 @@ def setUp(self):
def data_formatter_commands(self):
"""Test using Python synthetic children provider."""
- self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
- lldbutil.run_break_set_by_file_and_line(
- self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
-
- self.runCmd("run", RUN_SUCCEEDED)
-
- process = self.dbg.GetSelectedTarget().GetProcess()
- # The stop reason of the thread should be breakpoint.
- self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
- substrs=['stopped',
- 'stop reason = breakpoint'])
+ _, process, thread, _ = lldbutil.run_to_line_breakpoint(
+ self, lldb.SBFileSpec("main.cpp"), self.line)
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
@@ -72,6 +62,7 @@ def cleanup():
# now set up the synth
self.runCmd("script from fooSynthProvider import *")
self.runCmd("type synth add -l fooSynthProvider foo")
+ self.runCmd("type synth add -l wrapfooSynthProvider wrapfoo")
self.expect("type synthetic list foo", substrs=['fooSynthProvider'])
# note that the value of fake_a depends on target byte order
@@ -147,6 +138,10 @@ def cleanup():
substrs=['r = 45',
'fake_a = %d' % fake_a_val,
'a = 12'])
+ self.expect("frame variable --ptr-depth 1 wrapper",
+ substrs=['r = 45',
+ 'fake_a = %d' % fake_a_val,
+ 'a = 12'])
# now add a filter.. it should fail
self.expect("type filter add foo --child b --child j", error=True,
@@ -160,9 +155,24 @@ def cleanup():
substrs=['r = 45',
'fake_a = %d' % fake_a_val,
'a = 12'])
+ self.expect("frame variable --ptr-depth 1 wrapper",
+ substrs=['r = 45',
+ 'fake_a = %d' % fake_a_val,
+ 'a = 12'])
+
+ # Test that the custom dereference operator for `wrapfoo` works through
+ # the Python API. The synthetic children provider gets queried at
+ # slightly
diff erent times in this case.
+ wrapper_var = thread.GetSelectedFrame().FindVariable('wrapper')
+ foo_var = wrapper_var.Dereference()
+ self.assertEqual(foo_var.GetNumChildren(), 3)
+ self.assertEqual(foo_var.GetChildAtIndex(0).GetName(), 'a')
+ self.assertEqual(foo_var.GetChildAtIndex(1).GetName(), 'fake_a')
+ self.assertEqual(foo_var.GetChildAtIndex(2).GetName(), 'r')
# now delete the synth and add the filter
self.runCmd("type synth delete foo")
+ self.runCmd("type synth delete wrapfoo")
self.runCmd("type filter add foo --child b --child j")
self.expect('frame variable f00_1',
@@ -172,6 +182,10 @@ def cleanup():
substrs=['r = 45',
'fake_a = %d' % fake_a_val,
'a = 12'])
+ self.expect("frame variable --ptr-depth 1 wrapper", matching=False,
+ substrs=['r = 45',
+ 'fake_a = %d' % fake_a_val,
+ 'a = 12'])
# now add the synth and it should fail
self.expect("type synth add -l fooSynthProvider foo", error=True,
@@ -197,6 +211,10 @@ def cleanup():
substrs=['r = 45',
'fake_a = %d' % fake_a_val,
'a = 12'])
+ self.expect("frame variable --ptr-depth 1 wrapper",
+ substrs=['r = 45',
+ 'fake_a = %d' % fake_a_val,
+ 'a = 12'])
# check the listing
self.expect('type synth list',
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py
index 45fb00468e08..6ee749b720b2 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py
@@ -28,3 +28,29 @@ def get_child_index(self, name):
def update(self):
return True
+
+
+class wrapfooSynthProvider:
+
+ def __init__(self, valobj, dict):
+ self.valobj = valobj
+
+ def num_children(self):
+ return 1
+
+ def get_child_at_index(self, index):
+ if index == 0:
+ return self.valobj.GetChildMemberWithName('ptr')
+ if index == 1:
+ return self.valobj.GetChildMemberWithName('ptr').Dereference()
+ return None
+
+ def get_child_index(self, name):
+ if name == 'ptr':
+ return 0
+ if name == '$$dereference$$':
+ return 1
+ return -1
+
+ def update(self):
+ return True
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/main.cpp
index f45a2abfb9f1..5cf4b6345927 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/main.cpp
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/main.cpp
@@ -46,11 +46,17 @@ struct wrapint
wrapint(int X) : x(X) {}
};
+struct wrapfoo
+{
+ foo *ptr;
+};
+
int main()
{
foo f00_1(1);
foo *f00_ptr = new foo(12);
-
+ wrapfoo wrapper{f00_ptr};
+
f00_1.a++; // Set break point at this line.
wrapint test_cast('A' +
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 1dd9a6cf62c3..1e553596fcfc 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -2859,6 +2859,9 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
GetSyntheticValue()
->GetChildMemberWithName(ConstString("$$dereference$$"), true)
.get();
+ } else if (IsSynthetic()) {
+ m_deref_valobj =
+ GetChildMemberWithName(ConstString("$$dereference$$"), true).get();
}
if (m_deref_valobj) {
More information about the lldb-commits
mailing list