<rdar://problem/12523238> Commit 3 of 3

Changed all relevant test cases to verify that MightHaveChildren() works correctly for objects of interest
Added a bunch of convenience methods for test cases to use: target(), process(), thread() and frame() which mimic the lldb.X convenience variables
As a bonus, edited the documentation on the website to describe the new method available for synthetic children providers writers to implement!

That's all folks!

llvm-svn: 166535
This commit is contained in:
Enrico Granata 2012-10-24 01:23:57 +00:00
parent 53e767bf6b
commit 44818163ed
9 changed files with 75 additions and 2 deletions

View File

@ -141,6 +141,9 @@ class LibcxxListDataFormatterTestCase(TestBase):
'[2] = ', '3', '[2] = ', '3',
'[3] = ', '4']) '[3] = ', '4'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("numbers_list").MightHaveChildren(), "numbers_list.MightHaveChildren() says False for non empty!")
self.runCmd("type format delete int") self.runCmd("type format delete int")
self.runCmd("c") self.runCmd("c")
@ -151,6 +154,9 @@ class LibcxxListDataFormatterTestCase(TestBase):
'[1]', 'is', '[1]', 'is',
'[2]', 'smart']) '[2]', 'smart'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("text_list").MightHaveChildren(), "text_list.MightHaveChildren() says False for non empty!")
self.expect("p text_list", self.expect("p text_list",
substrs = ['list has 3 items', substrs = ['list has 3 items',
'\"goofy\"', '\"goofy\"',

View File

@ -118,6 +118,9 @@ class LibcxxMapDataFormatterTestCase(TestBase):
substrs = ['first =', substrs = ['first =',
'second =']); 'second =']);
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("ii").MightHaveChildren(), "ii.MightHaveChildren() says False for non empty!")
# check that the expression parser does not make use of # check that the expression parser does not make use of
# synthetic children instead of running code # synthetic children instead of running code
# TOT clang has a fix for this, which makes the expression command here succeed # TOT clang has a fix for this, which makes the expression command here succeed
@ -180,6 +183,9 @@ class LibcxxMapDataFormatterTestCase(TestBase):
'first = \"three\"', 'first = \"three\"',
'second = 3']) 'second = 3'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("si").MightHaveChildren(), "si.MightHaveChildren() says False for non empty!")
# check access-by-index # check access-by-index
self.expect("frame variable si[0]", self.expect("frame variable si[0]",
substrs = ['first = ', 'one', substrs = ['first = ', 'one',
@ -238,6 +244,9 @@ class LibcxxMapDataFormatterTestCase(TestBase):
'second = \"!!!\"', 'second = \"!!!\"',
'first = 3']) 'first = 3'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("is").MightHaveChildren(), "is.MightHaveChildren() says False for non empty!")
# check access-by-index # check access-by-index
self.expect("frame variable is[0]", self.expect("frame variable is[0]",
substrs = ['first = ', substrs = ['first = ',
@ -291,6 +300,9 @@ class LibcxxMapDataFormatterTestCase(TestBase):
'second = \"cat\"', 'second = \"cat\"',
'first = \"gatto\"']) 'first = \"gatto\"'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("ss").MightHaveChildren(), "ss.MightHaveChildren() says False for non empty!")
# check access-by-index # check access-by-index
self.expect("frame variable ss[2]", self.expect("frame variable ss[2]",
substrs = ['gatto', 'cat']); substrs = ['gatto', 'cat']);

View File

@ -132,6 +132,9 @@ class StdListDataFormatterTestCase(TestBase):
self.expect("expression numbers_list[0]", matching=False, error=True, self.expect("expression numbers_list[0]", matching=False, error=True,
substrs = ['0x12345678']) substrs = ['0x12345678'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("numbers_list").MightHaveChildren(), "numbers_list.MightHaveChildren() says False for non empty!")
self.runCmd("n") self.runCmd("n")
self.expect("frame variable numbers_list", self.expect("frame variable numbers_list",
@ -181,6 +184,9 @@ class StdListDataFormatterTestCase(TestBase):
self.expect("expression text_list[0]", matching=False, error=True, self.expect("expression text_list[0]", matching=False, error=True,
substrs = ['goofy']) substrs = ['goofy'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("text_list").MightHaveChildren(), "text_list.MightHaveChildren() says False for non empty!")
if __name__ == '__main__': if __name__ == '__main__':
import atexit import atexit
lldb.SBDebugger.Initialize() lldb.SBDebugger.Initialize()

View File

@ -118,6 +118,9 @@ class StdMapDataFormatterTestCase(TestBase):
self.expect("frame variable ii[8]", matching=True, self.expect("frame variable ii[8]", matching=True,
substrs = ['1234567']) substrs = ['1234567'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("ii").MightHaveChildren(), "ii.MightHaveChildren() says False for non empty!")
# check that the expression parser does not make use of # check that the expression parser does not make use of
# synthetic children instead of running code # synthetic children instead of running code
# TOT clang has a fix for this, which makes the expression command here succeed # TOT clang has a fix for this, which makes the expression command here succeed
@ -189,7 +192,10 @@ class StdMapDataFormatterTestCase(TestBase):
self.expect("frame variable si[0]", self.expect("frame variable si[0]",
substrs = ['first = ', 'four', substrs = ['first = ', 'four',
'second = 4']); 'second = 4']);
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("si").MightHaveChildren(), "si.MightHaveChildren() says False for non empty!")
# check that the expression parser does not make use of # check that the expression parser does not make use of
# synthetic children instead of running code # synthetic children instead of running code
# TOT clang has a fix for this, which makes the expression command here succeed # TOT clang has a fix for this, which makes the expression command here succeed
@ -247,7 +253,10 @@ class StdMapDataFormatterTestCase(TestBase):
self.expect("frame variable is[0]", self.expect("frame variable is[0]",
substrs = ['first = ', substrs = ['first = ',
'second =']); 'second =']);
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("is").MightHaveChildren(), "is.MightHaveChildren() says False for non empty!")
# check that the expression parser does not make use of # check that the expression parser does not make use of
# synthetic children instead of running code # synthetic children instead of running code
# TOT clang has a fix for this, which makes the expression command here succeed # TOT clang has a fix for this, which makes the expression command here succeed
@ -304,6 +313,9 @@ class StdMapDataFormatterTestCase(TestBase):
# check access-by-index # check access-by-index
self.expect("frame variable ss[3]", self.expect("frame variable ss[3]",
substrs = ['gatto', 'cat']); substrs = ['gatto', 'cat']);
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("ss").MightHaveChildren(), "ss.MightHaveChildren() says False for non empty!")
# check that the expression parser does not make use of # check that the expression parser does not make use of
# synthetic children instead of running code # synthetic children instead of running code

View File

@ -143,6 +143,9 @@ class StdVectorDataFormatterTestCase(TestBase):
self.expect("expression numbers[6]", matching=False, error=True, self.expect("expression numbers[6]", matching=False, error=True,
substrs = ['1234567']) substrs = ['1234567'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("numbers").MightHaveChildren(), "numbers.MightHaveChildren() says False for non empty!")
# clear out the vector and see that we do the right thing once again # clear out the vector and see that we do the right thing once again
self.runCmd("n") self.runCmd("n")
@ -204,6 +207,9 @@ class StdVectorDataFormatterTestCase(TestBase):
self.expect("expression strings[0]", matching=False, error=True, self.expect("expression strings[0]", matching=False, error=True,
substrs = ['goofy']) substrs = ['goofy'])
# check that MightHaveChildren() gets it right
self.assertTrue(self.frame().FindVariable("strings").MightHaveChildren(), "strings.MightHaveChildren() says False for non empty!")
self.runCmd("n") self.runCmd("n")
self.expect("frame variable strings", self.expect("frame variable strings",

View File

@ -72,6 +72,9 @@ class DataFormatterRdar11086338TestCase(TestBase):
self.expect('frame variable other_arr --ptr-depth 2 -d no-run-target', self.expect('frame variable other_arr --ptr-depth 2 -d no-run-target',
substrs = ['@"4 objects"','@"6 objects" {','@"hello"','@"world"','@"this"','@"is"','@"me"','@"http://www.apple.com']) substrs = ['@"4 objects"','@"6 objects" {','@"hello"','@"world"','@"this"','@"is"','@"me"','@"http://www.apple.com'])
self.assertTrue(self.frame().FindVariable("arr").MightHaveChildren(), "arr says it does not have children!")
self.assertTrue(self.frame().FindVariable("other_arr").MightHaveChildren(), "arr says it does not have children!")
if __name__ == '__main__': if __name__ == '__main__':
import atexit import atexit

View File

@ -74,6 +74,9 @@ class DataFormatterRdar11988289TestCase(TestBase):
self.expect('frame variable mutable --ptr-depth 3 -d no-run-target', self.expect('frame variable mutable --ptr-depth 3 -d no-run-target',
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs {','@"bar"','@"2 objects"','(int)1','@"two"']) substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs {','@"bar"','@"2 objects"','(int)1','@"two"'])
self.assertTrue(self.frame().FindVariable("dictionary").MightHaveChildren(), "dictionary says it does not have children!")
self.assertTrue(self.frame().FindVariable("mutable").MightHaveChildren(), "mutable says it does not have children!")
if __name__ == '__main__': if __name__ == '__main__':
import atexit import atexit

View File

@ -1021,6 +1021,27 @@ class TestBase(Base):
if lldb.pre_flight: if lldb.pre_flight:
lldb.pre_flight(self) lldb.pre_flight(self)
# utility methods that tests can use to access the current objects
def target(self):
if not self.dbg:
raise Exception('Invalid debugger instance')
return self.dbg.GetSelectedTarget()
def process(self):
if not self.dbg:
raise Exception('Invalid debugger instance')
return self.dbg.GetSelectedTarget().GetProcess()
def thread(self):
if not self.dbg:
raise Exception('Invalid debugger instance')
return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()
def frame(self):
if not self.dbg:
raise Exception('Invalid debugger instance')
return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
def tearDown(self): def tearDown(self):
#import traceback #import traceback
#traceback.print_stack() #traceback.print_stack()

View File

@ -1039,8 +1039,12 @@ def function (valobj,internal_dict):<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>this call should return a new LLDB SBValue object representing the child at the index given as argument</i> <br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>this call should return a new LLDB SBValue object representing the child at the index given as argument</i> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;<font color=blue>def</font> update(self): <br/> &nbsp;&nbsp;&nbsp;&nbsp;<font color=blue>def</font> update(self): <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.</i><sup>[1]</sup><br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.</i><sup>[1]</sup><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<font color=blue>def</font> has_children(self): <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>this call should return True if this object might have children, and False if this object can be guaranteed not to have children.</i><sup>[2]</sup><br/>
</code> </code>
<sup>[1]</sup> This method is optional. Also, it may optionally choose to return a value (starting with LLDB SVN rev153061/LLDB-134). If it returns a value, and that value is <font color=blue><code>True</code></font>, LLDB will be allowed to cache the children and the children count it previously obtained, and will not return to the provider class to ask. If nothing, <font color=blue><code>None</code></font>, or anything other than <font color=blue><code>True</code></font> is returned, LLDB will discard the cached information and ask. Regardless, whenever necessary LLDB will call <code>update</code>. <sup>[1]</sup> This method is optional. Also, it may optionally choose to return a value (starting with LLDB SVN rev153061/LLDB-134). If it returns a value, and that value is <font color=blue><code>True</code></font>, LLDB will be allowed to cache the children and the children count it previously obtained, and will not return to the provider class to ask. If nothing, <font color=blue><code>None</code></font>, or anything other than <font color=blue><code>True</code></font> is returned, LLDB will discard the cached information and ask. Regardless, whenever necessary LLDB will call <code>update</code>.
<br/>
<sup>[2]</sup> This method is optional, and LLDB will honor it starting with SVN rev166495. While implementing it in terms of <code>num_children</code> is acceptable, implementors are encouraged to look for optimized coding alternatives whenever reasonable. For an example, see the <code>std::list</code> providers shipping with LLDB.
<p>For examples of how synthetic children are created, you are encouraged to look at <a href="http://llvm.org/svn/llvm-project/lldb/trunk/examples/synthetic/">examples/synthetic</a> in the LLDB trunk. <p>For examples of how synthetic children are created, you are encouraged to look at <a href="http://llvm.org/svn/llvm-project/lldb/trunk/examples/synthetic/">examples/synthetic</a> in the LLDB trunk.
You may especially want to begin looking at <a href="http://llvm.org/svn/llvm-project/lldb/trunk/examples/synthetic/bitfield">this example</a> to get You may especially want to begin looking at <a href="http://llvm.org/svn/llvm-project/lldb/trunk/examples/synthetic/bitfield">this example</a> to get
a feel for this feature, as it is a very easy and well commented example.</p> a feel for this feature, as it is a very easy and well commented example.</p>