1 //===-- DumpValueObjectOptionsTests.cpp -----------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "Plugins/Platform/Linux/PlatformLinux.h"
10 #include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12 #include "TestingSupport/SubsystemRAII.h"
13 #include "TestingSupport/Symbol/ClangTestUtils.h"
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/DataFormatters/DumpValueObjectOptions.h"
16 #include "lldb/ValueObject/ValueObject.h"
17 #include "lldb/ValueObject/ValueObjectConstResult.h"
19 #include "gtest/gtest.h"
21 #include <type_traits>
24 using namespace lldb_private
;
26 struct MockProcess
: Process
{
27 MockProcess(lldb::TargetSP target_sp
, lldb::ListenerSP listener_sp
)
28 : Process(target_sp
, listener_sp
) {}
30 llvm::StringRef
GetPluginName() override
{ return "mock process"; }
32 bool CanDebug(lldb::TargetSP target
, bool plugin_specified_by_name
) override
{
36 Status
DoDestroy() override
{ return {}; }
38 void RefreshStateAfterStop() override
{}
40 bool DoUpdateThreadList(ThreadList
&old_thread_list
,
41 ThreadList
&new_thread_list
) override
{
45 size_t DoReadMemory(lldb::addr_t vm_addr
, void *buf
, size_t size
,
46 Status
&error
) override
{
47 // No need to read memory in these tests.
52 class ValueObjectMockProcessTest
: public ::testing::Test
{
54 void SetUp() override
{
55 ArchSpec
arch("i386-pc-linux");
56 Platform::SetHostPlatform(
57 platform_linux::PlatformLinux::CreateInstance(true, &arch
));
58 m_debugger_sp
= Debugger::CreateInstance();
59 ASSERT_TRUE(m_debugger_sp
);
60 m_debugger_sp
->GetTargetList().CreateTarget(*m_debugger_sp
, "", arch
,
62 m_platform_sp
, m_target_sp
);
63 ASSERT_TRUE(m_target_sp
);
64 ASSERT_TRUE(m_target_sp
->GetArchitecture().IsValid());
65 ASSERT_TRUE(m_platform_sp
);
66 m_listener_sp
= Listener::MakeListener("dummy");
67 m_process_sp
= std::make_shared
<MockProcess
>(m_target_sp
, m_listener_sp
);
68 ASSERT_TRUE(m_process_sp
);
69 m_exe_ctx
= ExecutionContext(m_process_sp
);
71 m_holder
= std::make_unique
<clang_utils::TypeSystemClangHolder
>("test");
72 m_type_system
= m_holder
->GetAST();
75 template <typename UnderlyingType
>
77 const std::vector
<std::pair
<const char *, UnderlyingType
>> enumerators
,
78 const std::vector
<std::tuple
<UnderlyingType
, DumpValueObjectOptions
,
79 const char *>> &tests
) {
80 CompilerType enum_type
= MakeEnumType(enumerators
);
82 ConstString
var_name("test_var");
83 ByteOrder endian
= endian::InlHostByteOrder();
84 ExecutionContextScope
*exe_scope
= m_exe_ctx
.GetBestExecutionContextScope();
85 for (auto [value
, options
, expected
] : tests
) {
86 DataExtractor data_extractor
{&value
, sizeof(value
), endian
, 4};
87 auto valobj_sp
= ValueObjectConstResult::Create(exe_scope
, enum_type
,
88 var_name
, data_extractor
);
89 if (llvm::Error error
= valobj_sp
->Dump(strm
, options
))
90 llvm::consumeError(std::move(error
));
91 ASSERT_STREQ(strm
.GetString().str().c_str(), expected
);
96 template <typename UnderlyingType
>
97 CompilerType
MakeEnumType(
98 const std::vector
<std::pair
<const char *, UnderlyingType
>> enumerators
) {
99 CompilerType int_type
= m_type_system
->GetBuiltinTypeForEncodingAndBitSize(
100 std::is_same
<UnderlyingType
, int>::value
? lldb::eEncodingSint
101 : lldb::eEncodingUint
,
103 CompilerType enum_type
= m_type_system
->CreateEnumerationType(
104 "TestEnum", m_type_system
->GetTranslationUnitDecl(),
105 OptionalClangModuleID(), Declaration(), int_type
, false);
107 m_type_system
->StartTagDeclarationDefinition(enum_type
);
109 for (auto [name
, value
] : enumerators
)
110 m_type_system
->AddEnumerationValueToEnumerationType(enum_type
, decl
, name
,
112 m_type_system
->CompleteTagDeclarationDefinition(enum_type
);
117 ExecutionContext m_exe_ctx
;
118 TypeSystemClang
*m_type_system
;
121 SubsystemRAII
<FileSystem
, HostInfo
, platform_linux::PlatformLinux
,
122 ScriptInterpreterNone
>
125 std::unique_ptr
<clang_utils::TypeSystemClangHolder
> m_holder
;
126 lldb::DebuggerSP m_debugger_sp
;
127 lldb::TargetSP m_target_sp
;
128 lldb::PlatformSP m_platform_sp
;
129 lldb::ListenerSP m_listener_sp
;
130 lldb::ProcessSP m_process_sp
;
133 TEST_F(ValueObjectMockProcessTest
, EmptyEnum
) {
134 // All values of an empty enum should be shown as plain numbers.
135 TestDumpEnum
<unsigned>({}, {{0, {}, "(TestEnum) test_var = 0\n"},
136 {1, {}, "(TestEnum) test_var = 1\n"},
137 {2, {}, "(TestEnum) test_var = 2\n"}});
139 TestDumpEnum
<int>({}, {{-2, {}, "(TestEnum) test_var = -2\n"},
140 {-1, {}, "(TestEnum) test_var = -1\n"},
141 {0, {}, "(TestEnum) test_var = 0\n"},
142 {1, {}, "(TestEnum) test_var = 1\n"},
143 {2, {}, "(TestEnum) test_var = 2\n"}});
146 TEST_F(ValueObjectMockProcessTest
, Enum
) {
147 // This is not a bitfield-like enum, so values are printed as decimal by
148 // default. Also we only show the enumerator name if the value is an
150 TestDumpEnum
<unsigned>(
151 {{"test_2", 2}, {"test_3", 3}},
152 {{0, {}, "(TestEnum) test_var = 0\n"},
153 {1, {}, "(TestEnum) test_var = 1\n"},
154 {2, {}, "(TestEnum) test_var = test_2\n"},
155 {3, {}, "(TestEnum) test_var = test_3\n"},
156 {4, {}, "(TestEnum) test_var = 4\n"},
157 {5, {}, "(TestEnum) test_var = 5\n"},
158 {1, DumpValueObjectOptions().SetHideRootName(true), "(TestEnum) 1\n"},
159 {1, DumpValueObjectOptions().SetHideRootType(true), "test_var = 1\n"},
160 {1, DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true),
162 {1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 1\n"},
163 {1, DumpValueObjectOptions().SetHideValue(true),
164 "(TestEnum) test_var =\n"},
165 {1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),
169 TEST_F(ValueObjectMockProcessTest
, BitFieldLikeEnum
) {
170 // These enumerators set individual bits in the value, as if it were a flag
171 // set. lldb treats this as a "bitfield like enum". This means we show values
172 // as hex, and values without exact matches are shown as a combination of
173 // enumerators and any remaining value left over.
174 TestDumpEnum
<unsigned>(
175 {{"test_2", 2}, {"test_4", 4}},
177 {0, {}, "(TestEnum) test_var = 0x0\n"},
178 {1, {}, "(TestEnum) test_var = 0x1\n"},
179 {2, {}, "(TestEnum) test_var = test_2\n"},
180 {4, {}, "(TestEnum) test_var = test_4\n"},
181 {6, {}, "(TestEnum) test_var = test_2 | test_4\n"},
182 {7, {}, "(TestEnum) test_var = test_2 | test_4 | 0x1\n"},
183 {8, {}, "(TestEnum) test_var = 0x8\n"},
184 {1, DumpValueObjectOptions().SetHideRootName(true),
186 {1, DumpValueObjectOptions().SetHideRootType(true),
189 DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true),
191 {1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 0x1\n"},
192 {1, DumpValueObjectOptions().SetHideValue(true),
193 "(TestEnum) test_var =\n"},
194 {1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),