Add data formatter for libstdc++ unique_ptr

Differential revision: https://reviews.llvm.org/D25734

llvm-svn: 284830
This commit is contained in:
Tamas Berghammer 2016-10-21 15:02:44 +00:00
parent 7f15dba16d
commit d161b2147b
7 changed files with 271 additions and 0 deletions

View File

@ -0,0 +1,8 @@
LEVEL = ../../../../../make
CXX_SOURCES := main.cpp
USE_LIBSTDCPP := 1
CFLAGS_EXTRAS += $(NO_LIMIT_DEBUG_INFO_FLAGS)
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,61 @@
"""
Test lldb data formatter subsystem.
"""
from __future__ import print_function
import os
import time
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class StdUniquePtrDataFormatterTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@skipIfFreeBSD
@skipIfWindows # libstdcpp not ported to Windows
@skipIfDarwin # doesn't compile on Darwin
def test_with_run_command(self):
self.build()
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
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'])
frame = self.frame()
self.assertTrue(frame.IsValid())
self.expect("frame variable nup", substrs=['nup = nullptr'])
self.expect("frame variable iup", substrs=['iup = 123', 'object = 123'])
self.expect("frame variable sup", substrs=['sup = "foobar"', 'object = "foobar"'])
self.expect("frame variable ndp", substrs=['ndp = nullptr'])
self.expect("frame variable idp", substrs=['idp = 456', 'object = 456', 'deleter = ', 'a = 1', 'b = 2'])
self.expect("frame variable sdp", substrs=['sdp = "baz"', 'object = "baz"', 'deleter = ', 'a = 3', 'b = 4'])
self.assertEqual(123, frame.GetValueForVariablePath("iup.object").GetValueAsUnsigned())
self.assertFalse(frame.GetValueForVariablePath("iup.deleter").IsValid())
self.assertEqual('"foobar"', frame.GetValueForVariablePath("sup.object").GetSummary())
self.assertFalse(frame.GetValueForVariablePath("sup.deleter").IsValid())
self.assertEqual(456, frame.GetValueForVariablePath("idp.object").GetValueAsUnsigned())
self.assertEqual('"baz"', frame.GetValueForVariablePath("sdp.object").GetSummary())
idp_deleter = frame.GetValueForVariablePath("idp.deleter")
self.assertTrue(idp_deleter.IsValid())
self.assertEqual(1, idp_deleter.GetChildMemberWithName("a").GetValueAsUnsigned())
self.assertEqual(2, idp_deleter.GetChildMemberWithName("b").GetValueAsUnsigned())
sdp_deleter = frame.GetValueForVariablePath("sdp.deleter")
self.assertTrue(sdp_deleter.IsValid())
self.assertEqual(3, sdp_deleter.GetChildMemberWithName("a").GetValueAsUnsigned())
self.assertEqual(4, sdp_deleter.GetChildMemberWithName("b").GetValueAsUnsigned())

View File

@ -0,0 +1,22 @@
#include <memory>
#include <string>
struct Deleter {
void operator()(void *) {}
int a;
int b;
};
int main() {
std::unique_ptr<char> nup;
std::unique_ptr<int> iup(new int{123});
std::unique_ptr<std::string> sup(new std::string("foobar"));
std::unique_ptr<char, Deleter> ndp;
std::unique_ptr<int, Deleter> idp(new int{456}, Deleter{1, 2});
std::unique_ptr<std::string, Deleter> sdp(new std::string("baz"),
Deleter{3, 4});
return 0; // Set break point at this line.
}

View File

@ -12,4 +12,5 @@ add_lldb_library(lldbPluginCPlusPlusLanguage
LibStdcpp.cpp
LibStdcppSmartPointer.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
)

View File

@ -801,6 +801,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::map iterator synthetic children",
ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
"std::unique_ptr synthetic children",
ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
@ -817,6 +822,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"),
stl_synth_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
"libstdc++ std::unique_ptr summary provider",
ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags,
true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
"libstdc++ std::shared_ptr summary provider",

View File

@ -31,6 +31,10 @@ bool LibStdcppSmartPointerSummaryProvider(
const TypeSummaryOptions
&options); // libstdc++ std::shared_ptr<> and std::weak_ptr<>
bool LibStdcppUniquePointerSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options); // libstdc++ std::unique_ptr<>
SyntheticChildrenFrontEnd *
LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
@ -46,6 +50,11 @@ LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
SyntheticChildrenFrontEnd *
LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
LibStdcppUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
} // namespace formatters
} // namespace lldb_private

View File

@ -0,0 +1,160 @@
//===-- LibStdcppUniquePointer.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "LibStdcpp.h"
#include <memory>
#include <vector>
#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
namespace {
class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
size_t CalculateNumChildren() override;
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
bool Update() override;
bool MightHaveChildren() override;
size_t GetIndexOfChildWithName(const ConstString &name) override;
bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
private:
ValueObjectSP m_ptr_obj;
ValueObjectSP m_obj_obj;
ValueObjectSP m_del_obj;
};
} // end of anonymous namespace
LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {
Update();
}
bool LibStdcppUniquePtrSyntheticFrontEnd::Update() {
ValueObjectSP valobj_backend_sp = m_backend.GetSP();
if (!valobj_backend_sp)
return false;
ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
if (!valobj_sp)
return false;
ValueObjectSP tuple_sp =
valobj_sp->GetChildMemberWithName(ConstString("_M_t"), true);
if (!tuple_sp)
return false;
std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
m_ptr_obj = tuple_frontend->GetChildAtIndex(0);
if (m_ptr_obj)
m_ptr_obj->SetName(ConstString("pointer"));
m_del_obj = tuple_frontend->GetChildAtIndex(1);
if (m_del_obj)
m_del_obj->SetName(ConstString("deleter"));
if (m_ptr_obj) {
Error error;
m_obj_obj = m_ptr_obj->Dereference(error);
if (error.Success()) {
m_obj_obj->SetName(ConstString("object"));
}
}
return false;
}
bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; }
lldb::ValueObjectSP
LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
if (idx == 0)
return m_obj_obj;
if (idx == 1)
return m_del_obj;
if (idx == 2)
return m_ptr_obj;
return lldb::ValueObjectSP();
}
size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
if (m_del_obj)
return 2;
if (m_ptr_obj && m_ptr_obj->GetValueAsUnsigned(0) != 0)
return 1;
return 0;
}
size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(
const ConstString &name) {
if (name == ConstString("obj") || name == ConstString("object"))
return 0;
if (name == ConstString("del") || name == ConstString("deleter"))
return 1;
if (name == ConstString("ptr") || name == ConstString("pointer"))
return 2;
return UINT32_MAX;
}
bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
Stream &stream, const TypeSummaryOptions &options) {
if (!m_ptr_obj)
return false;
if (m_ptr_obj->GetValueAsUnsigned(0) == 0) {
stream.Printf("nullptr");
} else {
Error error;
bool print_pointee = false;
if (m_obj_obj) {
if (m_obj_obj->DumpPrintableRepresentation(
stream, ValueObject::eValueObjectRepresentationStyleSummary,
lldb::eFormatInvalid,
ValueObject::ePrintableRepresentationSpecialCasesDisable,
false)) {
print_pointee = true;
}
}
if (!print_pointee)
stream.Printf("ptr = 0x%" PRIx64, m_ptr_obj->GetValueAsUnsigned(0));
}
return true;
}
SyntheticChildrenFrontEnd *
lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
: nullptr);
}
bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
return formatter.GetSummary(stream, options);
}