Skip to content

Commit

Permalink
Fix the libcxx set, multiset, vector and bitset formatters to work on…
Browse files Browse the repository at this point in the history
… references.

The synthetic child providers for these classes had a type expression that matched
pointers & references to the type, but the Front End only worked on the actual object.

I fixed this by adding a way for the Synthetic Child FrontEnd provider to request dereference,
and then had these formatters use that mode.

<rdar://problem/40849836>

Differential Revision: https://reviews.llvm.org/D49279

llvm-svn: 337035
  • Loading branch information
jimingham committed Jul 13, 2018
1 parent 0925c1f commit 393fe62
Showing 12 changed files with 239 additions and 126 deletions.
15 changes: 15 additions & 0 deletions lldb/include/lldb/DataFormatters/TypeSynthetic.h
Original file line number Diff line number Diff line change
@@ -207,6 +207,19 @@ class SyntheticChildren {
return *this;
}

bool GetFrontEndWantsDereference() const {
return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) ==
lldb::eTypeOptionFrontEndWantsDereference;
}

Flags &SetFrontEndWantsDereference(bool value = true) {
if (value)
m_flags |= lldb::eTypeOptionFrontEndWantsDereference;
else
m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference;
return *this;
}

uint32_t GetValue() { return m_flags; }

void SetValue(uint32_t value) { m_flags = value; }
@@ -226,6 +239,8 @@ class SyntheticChildren {
bool SkipsReferences() const { return m_flags.GetSkipReferences(); }

bool NonCacheable() const { return m_flags.GetNonCacheable(); }

bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();}

void SetCascades(bool value) { m_flags.SetCascades(value); }

4 changes: 3 additions & 1 deletion lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
@@ -789,7 +789,9 @@ FLAGS_ENUM(TypeOptions){eTypeOptionNone = (0u),
eTypeOptionShowOneLiner = (1u << 5),
eTypeOptionHideNames = (1u << 6),
eTypeOptionNonCacheable = (1u << 7),
eTypeOptionHideEmptyAggregates = (1u << 8)};
eTypeOptionHideEmptyAggregates = (1u << 8),
eTypeOptionFrontEndWantsDereference = (1u << 9)
};

//----------------------------------------------------------------------
// This is the return value for frame comparisons. If you are comparing frame
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ def check(self, name, size):
"variable: %s, index: %d"%(name, size))

@add_test_categories(["libc++"])
def test(self):
def test_value(self):
"""Test that std::bitset is displayed correctly"""
self.build()
lldbutil.run_to_source_breakpoint(self, '// break here',
@@ -44,3 +44,18 @@ def test(self):
self.check("empty", 0)
self.check("small", 13)
self.check("large", 200)

def test_ptr_and_ref(self):
"""Test that ref and ptr to std::bitset is displayed correctly"""
self.build()
(_, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self,
'Check ref and ptr',
lldb.SBFileSpec("main.cpp", False))

self.check("ref", 13)
self.check("ptr", 13)

lldbutil.continue_to_breakpoint(process, bkpt)

self.check("ref", 200)
self.check("ptr", 200)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <bitset>
#include <stdio.h>

template<std::size_t N>
void fill(std::bitset<N> &b) {
@@ -10,11 +11,19 @@ void fill(std::bitset<N> &b) {
}
}

template<std::size_t N>
void by_ref_and_ptr(std::bitset<N> &ref, std::bitset<N> *ptr) {
// Check ref and ptr
return;
}

int main() {
std::bitset<0> empty;
std::bitset<13> small;
fill(small);
std::bitset<200> large;
fill(large);
return 0; // break here
by_ref_and_ptr(small, &small); // break here
by_ref_and_ptr(large, &large);
return 0;
}
Original file line number Diff line number Diff line change
@@ -27,22 +27,31 @@ def getVariableType(self, name):
self.assertTrue(var.IsValid())
return var.GetType().GetCanonicalType().GetName()

def check_ii(self, var_name):
""" This checks the value of the bitset stored in ii at the call to by_ref_and_ptr.
We use this to make sure we get the same values for ii when we look at the object
directly, and when we look at a reference to the object. """
self.expect(
"frame variable " + var_name,
substrs=["size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])
self.expect("frame variable " + var_name + "[2]", substrs=[" = 2"])
self.expect(
"p " + var_name,
substrs=[
"size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])

@add_test_categories(["libc++"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
self.build()
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)

bkpt = self.target().FindBreakpointByID(
lldbutil.run_break_set_by_source_regexp(
self, "Set break point at this line."))

self.runCmd("run", RUN_SUCCEEDED)

# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs=['stopped',
'stop reason = breakpoint'])
(self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp", False))

# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
@@ -63,7 +72,7 @@ def cleanup():
"Type: " + ii_type)

self.expect("frame variable ii", substrs=["size=0", "{}"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ii",
substrs=[
@@ -74,38 +83,26 @@ def cleanup():
"[3] = 3",
"[4] = 4",
"[5] = 5"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
self.expect(
"frame variable ii",
substrs=[
"size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])
self.expect(
"p ii",
substrs=[
"size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])
self.expect("frame variable ii[2]", substrs=[" = 2"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)

self.check_ii("ii")

lldbutil.continue_to_breakpoint(process, bkpt)
self.expect("frame variable ii", substrs=["size=0", "{}"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect("frame variable ii", substrs=["size=0", "{}"])
ss_type = self.getVariableType("ss")
self.assertTrue(ss_type.startswith(self.namespace + "::multiset"),
"Type: " + ss_type)
self.expect("frame variable ss", substrs=["size=0", "{}"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ss",
substrs=[
"size=2",
'[0] = "a"',
'[1] = "a very long string is right here"'])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ss",
substrs=[
@@ -123,11 +120,26 @@ def cleanup():
'[0] = "a"',
'[1] = "a very long string is right here"'])
self.expect("frame variable ss[2]", substrs=[' = "b"'])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ss",
substrs=[
"size=3",
'[0] = "a"',
'[1] = "a very long string is right here"',
'[2] = "c"'])

@add_test_categories(["libc++"])
def test_ref_and_ptr(self):
"""Test that the data formatters work on ref and ptr."""
self.build()
(self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Stop here to check by ref and ptr.",
lldb.SBFileSpec("main.cpp", False))
# The reference should print just like the value:
self.check_ii("ref")

self.expect("frame variable ptr",
substrs=["ptr =", "size=7"])
self.expect("expr ptr",
substrs=["size=7"])
Original file line number Diff line number Diff line change
@@ -16,6 +16,12 @@ int thefoo_rw(int arg = 1)
return g_the_foo;
}

void by_ref_and_ptr(intset &ref, intset *ptr)
{
// Stop here to check by ref and ptr
return;
}

int main()
{
intset ii;
@@ -31,7 +37,9 @@ int main()

ii.insert(6);
thefoo_rw(1); // Set break point at this line.


by_ref_and_ptr(ii, &ii);

ii.clear();
thefoo_rw(1); // Set break point at this line.

Original file line number Diff line number Diff line change
@@ -27,21 +27,31 @@ def getVariableType(self, name):
self.assertTrue(var.IsValid())
return var.GetType().GetCanonicalType().GetName()

def check_ii(self, var_name):
""" This checks the value of the bitset stored in ii at the call to by_ref_and_ptr.
We use this to make sure we get the same values for ii when we look at the object
directly, and when we look at a reference to the object. """
self.expect(
"frame variable " + var_name,
substrs=["size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])
self.expect("frame variable " + var_name + "[2]", substrs=[" = 2"])
self.expect(
"p " + var_name,
substrs=[
"size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])

@add_test_categories(["libc++"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
self.build()
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)

bkpt = self.target().FindBreakpointByID(
lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line."))

self.runCmd("run", RUN_SUCCEEDED)

# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs=['stopped',
'stop reason = breakpoint'])
(self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp", False))

# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
@@ -62,7 +72,7 @@ def cleanup():
"Type: " + ii_type)

self.expect("frame variable ii", substrs=["size=0", "{}"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ii",
substrs=["size=6",
@@ -72,38 +82,26 @@ def cleanup():
"[3] = 3",
"[4] = 4",
"[5] = 5"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
self.expect(
"frame variable ii",
substrs=["size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])
self.expect("frame variable ii[2]", substrs=[" = 2"])
self.expect(
"p ii",
substrs=[
"size=7",
"[2] = 2",
"[3] = 3",
"[6] = 6"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.check_ii("ii")

lldbutil.continue_to_breakpoint(process, bkpt)
self.expect("frame variable ii", substrs=["size=0", "{}"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect("frame variable ii", substrs=["size=0", "{}"])

ss_type = self.getVariableType("ss")
self.assertTrue(ii_type.startswith(self.namespace + "::set"),
"Type: " + ss_type)

self.expect("frame variable ss", substrs=["size=0", "{}"])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ss",
substrs=["size=2",
'[0] = "a"',
'[1] = "a very long string is right here"'])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ss",
substrs=["size=4",
@@ -119,10 +117,26 @@ def cleanup():
'[0] = "a"',
'[1] = "a very long string is right here"'])
self.expect("frame variable ss[2]", substrs=[' = "b"'])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect(
"frame variable ss",
substrs=["size=3",
'[0] = "a"',
'[1] = "a very long string is right here"',
'[2] = "c"'])

@add_test_categories(["libc++"])
def test_ref_and_ptr(self):
"""Test that the data formatters work on ref and ptr."""
self.build()
(self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Stop here to check by ref and ptr.",
lldb.SBFileSpec("main.cpp", False))
# The reference should print just like the value:
self.check_ii("ref")

self.expect("frame variable ptr",
substrs=["ptr =", "size=7"])
self.expect("expr ptr",
substrs=["size=7"])

Original file line number Diff line number Diff line change
@@ -16,6 +16,12 @@ int thefoo_rw(int arg = 1)
return g_the_foo;
}

void by_ref_and_ptr(intset &ref, intset *ptr)
{
// Stop here to check by ref and ptr
return;
}

int main()
{
intset ii;
@@ -31,7 +37,9 @@ int main()

ii.insert(6);
thefoo_rw(1); // Set break point at this line.


by_ref_and_ptr(ii, &ii);

ii.clear();
thefoo_rw(1); // Set break point at this line.

Loading

0 comments on commit 393fe62

Please sign in to comment.