Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DataFormatters] Add formatter for C++17 std::optional.
<rdar://problem/41471112> Patch by Shafik Yaghmour. Differential Revision: https://reviews.llvm.org/D49271 llvm-svn: 337959
- Loading branch information
Showing
4 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
...lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/Makefile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
LEVEL = ../../../../../make | ||
|
||
CXX_SOURCES := main.cpp | ||
|
||
USE_LIBCPP := 1 | ||
include $(LEVEL)/Makefile.rules | ||
CXXFLAGS += -std=c++17 |
59 changes: 59 additions & 0 deletions
59
...ties/data-formatter/data-formatter-stl/libcxx/optional/TestDataFormatterLibcxxOptional.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
""" | ||
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 LibcxxOptionalDataFormatterTestCase(TestBase): | ||
|
||
mydir = TestBase.compute_mydir(__file__) | ||
|
||
@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, "break here")) | ||
|
||
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.expect("frame variable number_not_engaged", | ||
substrs=['Has Value=false']) | ||
|
||
self.expect("frame variable number_engaged", | ||
substrs=['Has Value=true', | ||
'Value = 42', | ||
'}']) | ||
|
||
self.expect("frame var numbers", | ||
substrs=['(optional_int_vect) numbers = Has Value=true {', | ||
'Value = size=4 {', | ||
'[0] = 1', | ||
'[1] = 2', | ||
'[2] = 3', | ||
'[3] = 4', | ||
'}', | ||
'}']) | ||
|
||
self.expect("frame var ostring", | ||
substrs=['(optional_string) ostring = Has Value=true {', | ||
'Value = "hello"', | ||
'}']) |
27 changes: 27 additions & 0 deletions
27
...lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/main.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#include <cstdio> | ||
#include <string> | ||
#include <vector> | ||
#include <optional> | ||
|
||
using int_vect = std::vector<int> ; | ||
using optional_int = std::optional<int> ; | ||
using optional_int_vect = std::optional<int_vect> ; | ||
using optional_string = std::optional<std::string> ; | ||
|
||
int main() | ||
{ | ||
optional_int number_not_engaged ; | ||
optional_int number_engaged = 42 ; | ||
|
||
printf( "%d\n", *number_engaged) ; | ||
|
||
optional_int_vect numbers{{1,2,3,4}} ; | ||
|
||
printf( "%d %d\n", numbers.value()[0], numbers.value()[1] ) ; | ||
|
||
optional_string ostring = "hello" ; | ||
|
||
printf( "%s\n", ostring->c_str() ) ; | ||
|
||
return 0; // break here | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
//===-- LibCxxOptional.cpp --------------------------------------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "LibCxx.h" | ||
#include "lldb/DataFormatters/FormattersHelpers.h" | ||
|
||
using namespace lldb; | ||
using namespace lldb_private; | ||
|
||
namespace { | ||
|
||
class OptionalFrontEnd : public SyntheticChildrenFrontEnd { | ||
public: | ||
OptionalFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) { | ||
Update(); | ||
} | ||
|
||
size_t GetIndexOfChildWithName(const ConstString &name) override { | ||
return formatters::ExtractIndexFromString(name.GetCString()); | ||
} | ||
|
||
bool MightHaveChildren() override { return true; } | ||
bool Update() override; | ||
size_t CalculateNumChildren() override { return m_size; } | ||
ValueObjectSP GetChildAtIndex(size_t idx) override; | ||
|
||
private: | ||
size_t m_size = 0; | ||
ValueObjectSP m_base_sp; | ||
}; | ||
} // namespace | ||
|
||
bool OptionalFrontEnd::Update() { | ||
ValueObjectSP engaged_sp( | ||
m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)); | ||
|
||
if (!engaged_sp) | ||
return false; | ||
|
||
// __engaged_ is a bool flag and is true if the optional contains a value. | ||
// Converting it to unsigned gives us a size of 1 if it contains a value | ||
// and 0 if not. | ||
m_size = engaged_sp->GetValueAsUnsigned(0); | ||
|
||
return false; | ||
} | ||
|
||
ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) { | ||
if (idx >= m_size) | ||
return ValueObjectSP(); | ||
|
||
// __val_ contains the underlying value of an optional if it has one. | ||
// Currently because it is part of an anonymous union GetChildMemberWithName() | ||
// does not peer through and find it unless we are at the parent itself. | ||
// We can obtain the parent through __engaged_. | ||
ValueObjectSP val_sp( | ||
m_backend.GetChildMemberWithName(ConstString("__engaged_"), true) | ||
->GetParent() | ||
->GetChildAtIndex(0, true) | ||
->GetChildMemberWithName(ConstString("__val_"), true)); | ||
|
||
if (!val_sp) | ||
return ValueObjectSP(); | ||
|
||
CompilerType holder_type = val_sp->GetCompilerType(); | ||
|
||
if (!holder_type) | ||
return ValueObjectSP(); | ||
|
||
return val_sp->Clone(ConstString(llvm::formatv("Value").str())); | ||
} | ||
|
||
SyntheticChildrenFrontEnd * | ||
formatters::LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, | ||
lldb::ValueObjectSP valobj_sp) { | ||
if (valobj_sp) | ||
return new OptionalFrontEnd(*valobj_sp); | ||
return nullptr; | ||
} |