1 //===-- OptionValueProperties.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 "lldb/Interpreter/OptionValueProperties.h"
11 #include "lldb/Utility/Flags.h"
13 #include "lldb/Core/UserSettingsController.h"
14 #include "lldb/Interpreter/OptionValues.h"
15 #include "lldb/Interpreter/Property.h"
16 #include "lldb/Utility/Args.h"
17 #include "lldb/Utility/Stream.h"
18 #include "lldb/Utility/StringList.h"
21 using namespace lldb_private
;
23 OptionValueProperties::OptionValueProperties(llvm::StringRef name
)
24 : m_name(name
.str()) {}
26 void OptionValueProperties::Initialize(const PropertyDefinitions
&defs
) {
27 for (const auto &definition
: defs
) {
28 Property
property(definition
);
29 assert(property
.IsValid());
30 m_name_to_index
.insert({property
.GetName(), m_properties
.size()});
31 property
.GetValue()->SetParent(shared_from_this());
32 m_properties
.push_back(property
);
36 void OptionValueProperties::SetValueChangedCallback(
37 size_t property_idx
, std::function
<void()> callback
) {
38 Property
*property
= ProtectedGetPropertyAtIndex(property_idx
);
40 property
->SetValueChangedCallback(std::move(callback
));
43 void OptionValueProperties::AppendProperty(llvm::StringRef name
,
44 llvm::StringRef desc
, bool is_global
,
45 const OptionValueSP
&value_sp
) {
46 Property
property(name
, desc
, is_global
, value_sp
);
47 m_name_to_index
.insert({name
, m_properties
.size()});
48 m_properties
.push_back(property
);
49 value_sp
->SetParent(shared_from_this());
53 OptionValueProperties::GetValueForKey(const ExecutionContext
*exe_ctx
,
54 llvm::StringRef key
) const {
55 auto iter
= m_name_to_index
.find(key
);
56 if (iter
== m_name_to_index
.end())
57 return OptionValueSP();
58 const size_t idx
= iter
->second
;
59 if (idx
>= m_properties
.size())
60 return OptionValueSP();
61 return GetPropertyAtIndex(idx
, exe_ctx
)->GetValue();
65 OptionValueProperties::GetSubValue(const ExecutionContext
*exe_ctx
,
66 llvm::StringRef name
, Status
&error
) const {
67 lldb::OptionValueSP value_sp
;
69 return OptionValueSP();
71 llvm::StringRef sub_name
;
73 size_t key_len
= name
.find_first_of(".[{");
74 if (key_len
!= llvm::StringRef::npos
) {
75 key
= name
.take_front(key_len
);
76 sub_name
= name
.drop_front(key_len
);
80 value_sp
= GetValueForKey(exe_ctx
, key
);
81 if (sub_name
.empty() || !value_sp
)
84 switch (sub_name
[0]) {
86 lldb::OptionValueSP return_val_sp
;
88 value_sp
->GetSubValue(exe_ctx
, sub_name
.drop_front(), error
);
90 if (Properties::IsSettingExperimental(sub_name
.drop_front())) {
91 const size_t experimental_len
=
92 Properties::GetExperimentalSettingsName().size();
93 if (sub_name
[experimental_len
+ 1] == '.')
94 return_val_sp
= value_sp
->GetSubValue(
95 exe_ctx
, sub_name
.drop_front(experimental_len
+ 2), error
);
96 // It isn't an error if an experimental setting is not present.
101 return return_val_sp
;
104 // Array or dictionary access for subvalues like: "[12]" -- access
105 // 12th array element "['hello']" -- dictionary access of key named hello
106 return value_sp
->GetSubValue(exe_ctx
, sub_name
, error
);
115 Status
OptionValueProperties::SetSubValue(const ExecutionContext
*exe_ctx
,
116 VarSetOperationType op
,
117 llvm::StringRef name
,
118 llvm::StringRef value
) {
120 llvm::SmallVector
<llvm::StringRef
, 8> components
;
121 name
.split(components
, '.');
122 bool name_contains_experimental
= false;
123 for (const auto &part
: components
)
124 if (Properties::IsSettingExperimental(part
))
125 name_contains_experimental
= true;
127 lldb::OptionValueSP
value_sp(GetSubValue(exe_ctx
, name
, error
));
129 error
= value_sp
->SetValueFromString(value
, op
);
131 // Don't set an error if the path contained .experimental. - those are
132 // allowed to be missing and should silently fail.
133 if (!name_contains_experimental
&& error
.AsCString() == nullptr) {
134 error
= Status::FromErrorStringWithFormat("invalid value path '%s'",
141 size_t OptionValueProperties::GetPropertyIndex(llvm::StringRef name
) const {
142 auto iter
= m_name_to_index
.find(name
);
143 if (iter
== m_name_to_index
.end())
149 OptionValueProperties::GetProperty(llvm::StringRef name
,
150 const ExecutionContext
*exe_ctx
) const {
151 auto iter
= m_name_to_index
.find(name
);
152 if (iter
== m_name_to_index
.end())
154 return GetPropertyAtIndex(iter
->second
, exe_ctx
);
157 lldb::OptionValueSP
OptionValueProperties::GetPropertyValueAtIndex(
158 size_t idx
, const ExecutionContext
*exe_ctx
) const {
159 const Property
*setting
= GetPropertyAtIndex(idx
, exe_ctx
);
161 return setting
->GetValue();
162 return OptionValueSP();
165 OptionValuePathMappings
*
166 OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings(
167 size_t idx
, const ExecutionContext
*exe_ctx
) const {
168 OptionValueSP
value_sp(GetPropertyValueAtIndex(idx
, exe_ctx
));
170 return value_sp
->GetAsPathMappings();
174 OptionValueFileSpecList
*
175 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList(
176 size_t idx
, const ExecutionContext
*exe_ctx
) const {
177 OptionValueSP
value_sp(GetPropertyValueAtIndex(idx
, exe_ctx
));
179 return value_sp
->GetAsFileSpecList();
183 bool OptionValueProperties::GetPropertyAtIndexAsArgs(
184 size_t idx
, Args
&args
, const ExecutionContext
*exe_ctx
) const {
185 const Property
*property
= GetPropertyAtIndex(idx
, exe_ctx
);
189 OptionValue
*value
= property
->GetValue().get();
193 const OptionValueArgs
*arguments
= value
->GetAsArgs();
195 arguments
->GetArgs(args
);
199 const OptionValueArray
*array
= value
->GetAsArray();
201 array
->GetArgs(args
);
205 const OptionValueDictionary
*dict
= value
->GetAsDictionary();
214 bool OptionValueProperties::SetPropertyAtIndexFromArgs(
215 size_t idx
, const Args
&args
, const ExecutionContext
*exe_ctx
) {
216 const Property
*property
= GetPropertyAtIndex(idx
, exe_ctx
);
220 OptionValue
*value
= property
->GetValue().get();
224 OptionValueArgs
*arguments
= value
->GetAsArgs();
226 return arguments
->SetArgs(args
, eVarSetOperationAssign
).Success();
228 OptionValueArray
*array
= value
->GetAsArray();
230 return array
->SetArgs(args
, eVarSetOperationAssign
).Success();
232 OptionValueDictionary
*dict
= value
->GetAsDictionary();
234 return dict
->SetArgs(args
, eVarSetOperationAssign
).Success();
239 OptionValueDictionary
*
240 OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary(
241 size_t idx
, const ExecutionContext
*exe_ctx
) const {
242 const Property
*property
= GetPropertyAtIndex(idx
, exe_ctx
);
244 return property
->GetValue()->GetAsDictionary();
248 OptionValueFileSpec
*
249 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec(
250 size_t idx
, const ExecutionContext
*exe_ctx
) const {
251 const Property
*property
= GetPropertyAtIndex(idx
, exe_ctx
);
253 OptionValue
*value
= property
->GetValue().get();
255 return value
->GetAsFileSpec();
260 OptionValueSInt64
*OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64(
261 size_t idx
, const ExecutionContext
*exe_ctx
) const {
262 const Property
*property
= GetPropertyAtIndex(idx
, exe_ctx
);
264 OptionValue
*value
= property
->GetValue().get();
266 return value
->GetAsSInt64();
271 OptionValueUInt64
*OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64(
272 size_t idx
, const ExecutionContext
*exe_ctx
) const {
273 const Property
*property
= GetPropertyAtIndex(idx
, exe_ctx
);
275 OptionValue
*value
= property
->GetValue().get();
277 return value
->GetAsUInt64();
282 OptionValueString
*OptionValueProperties::GetPropertyAtIndexAsOptionValueString(
283 size_t idx
, const ExecutionContext
*exe_ctx
) const {
284 OptionValueSP
value_sp(GetPropertyValueAtIndex(idx
, exe_ctx
));
286 return value_sp
->GetAsString();
290 void OptionValueProperties::Clear() {
291 const size_t num_properties
= m_properties
.size();
292 for (size_t i
= 0; i
< num_properties
; ++i
)
293 m_properties
[i
].GetValue()->Clear();
296 Status
OptionValueProperties::SetValueFromString(llvm::StringRef value
,
297 VarSetOperationType op
) {
300 // Args args(value_cstr);
301 // const size_t argc = args.GetArgumentCount();
303 case eVarSetOperationClear
:
307 case eVarSetOperationReplace
:
308 case eVarSetOperationAssign
:
309 case eVarSetOperationRemove
:
310 case eVarSetOperationInsertBefore
:
311 case eVarSetOperationInsertAfter
:
312 case eVarSetOperationAppend
:
313 case eVarSetOperationInvalid
:
314 error
= OptionValue::SetValueFromString(value
, op
);
321 void OptionValueProperties::DumpValue(const ExecutionContext
*exe_ctx
,
322 Stream
&strm
, uint32_t dump_mask
) {
323 const size_t num_properties
= m_properties
.size();
324 for (size_t i
= 0; i
< num_properties
; ++i
) {
325 const Property
*property
= GetPropertyAtIndex(i
, exe_ctx
);
327 OptionValue
*option_value
= property
->GetValue().get();
328 assert(option_value
);
329 const bool transparent_value
= option_value
->ValueIsTransparent();
330 property
->Dump(exe_ctx
, strm
, dump_mask
);
331 if (!transparent_value
)
338 OptionValueProperties::ToJSON(const ExecutionContext
*exe_ctx
) {
339 llvm::json::Object json_properties
;
340 const size_t num_properties
= m_properties
.size();
341 for (size_t i
= 0; i
< num_properties
; ++i
) {
342 const Property
*property
= GetPropertyAtIndex(i
, exe_ctx
);
344 OptionValue
*option_value
= property
->GetValue().get();
345 assert(option_value
);
346 json_properties
.try_emplace(property
->GetName(),
347 option_value
->ToJSON(exe_ctx
));
350 return json_properties
;
353 Status
OptionValueProperties::DumpPropertyValue(const ExecutionContext
*exe_ctx
,
355 llvm::StringRef property_path
,
359 lldb::OptionValueSP
value_sp(GetSubValue(exe_ctx
, property_path
, error
));
361 if (!value_sp
->ValueIsTransparent()) {
362 if (dump_mask
& eDumpOptionName
)
363 strm
.PutCString(property_path
);
364 if (dump_mask
& ~eDumpOptionName
)
370 llvm::formatv("{0:2}", value_sp
->ToJSON(exe_ctx
)).str().c_str());
372 value_sp
->DumpValue(exe_ctx
, strm
, dump_mask
);
377 OptionValuePropertiesSP
378 OptionValueProperties::CreateLocalCopy(const Properties
&global_properties
) {
379 auto global_props_sp
= global_properties
.GetValueProperties();
380 lldbassert(global_props_sp
);
382 auto copy_sp
= global_props_sp
->DeepCopy(global_props_sp
->GetParent());
383 return std::static_pointer_cast
<OptionValueProperties
>(copy_sp
);
387 OptionValueProperties::DeepCopy(const OptionValueSP
&new_parent
) const {
388 auto copy_sp
= OptionValue::DeepCopy(new_parent
);
389 // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived
390 // types that override GetType returning a different value.
391 auto *props_value_ptr
= static_cast<OptionValueProperties
*>(copy_sp
.get());
392 lldbassert(props_value_ptr
);
394 for (auto &property
: props_value_ptr
->m_properties
) {
395 // Duplicate any values that are not global when constructing properties
396 // from a global copy.
397 if (!property
.IsGlobal()) {
398 auto value_sp
= property
.GetValue()->DeepCopy(copy_sp
);
399 property
.SetOptionValue(value_sp
);
406 OptionValueProperties::GetPropertyAtPath(const ExecutionContext
*exe_ctx
,
407 llvm::StringRef name
) const {
411 const Property
*property
= nullptr;
412 llvm::StringRef sub_name
;
414 size_t key_len
= name
.find_first_of(".[{");
416 if (key_len
!= llvm::StringRef::npos
) {
417 key
= name
.take_front(key_len
);
418 sub_name
= name
.drop_front(key_len
);
422 property
= GetProperty(key
, exe_ctx
);
423 if (sub_name
.empty() || !property
)
426 if (sub_name
[0] == '.') {
427 OptionValueProperties
*sub_properties
=
428 property
->GetValue()->GetAsProperties();
430 return sub_properties
->GetPropertyAtPath(exe_ctx
, sub_name
.drop_front());
435 void OptionValueProperties::DumpAllDescriptions(CommandInterpreter
&interpreter
,
436 Stream
&strm
) const {
437 size_t max_name_len
= 0;
438 const size_t num_properties
= m_properties
.size();
439 for (size_t i
= 0; i
< num_properties
; ++i
) {
440 const Property
*property
= ProtectedGetPropertyAtIndex(i
);
442 max_name_len
= std::max
<size_t>(property
->GetName().size(), max_name_len
);
444 for (size_t i
= 0; i
< num_properties
; ++i
) {
445 const Property
*property
= ProtectedGetPropertyAtIndex(i
);
447 property
->DumpDescription(interpreter
, strm
, max_name_len
, false);
451 void OptionValueProperties::Apropos(
452 llvm::StringRef keyword
,
453 std::vector
<const Property
*> &matching_properties
) const {
454 const size_t num_properties
= m_properties
.size();
456 for (size_t i
= 0; i
< num_properties
; ++i
) {
457 const Property
*property
= ProtectedGetPropertyAtIndex(i
);
459 const OptionValueProperties
*properties
=
460 property
->GetValue()->GetAsProperties();
462 properties
->Apropos(keyword
, matching_properties
);
465 llvm::StringRef name
= property
->GetName();
466 if (name
.contains_insensitive(keyword
))
469 llvm::StringRef desc
= property
->GetDescription();
470 if (desc
.contains_insensitive(keyword
))
474 matching_properties
.push_back(property
);
481 lldb::OptionValuePropertiesSP
482 OptionValueProperties::GetSubProperty(const ExecutionContext
*exe_ctx
,
483 llvm::StringRef name
) {
484 lldb::OptionValueSP
option_value_sp(GetValueForKey(exe_ctx
, name
));
485 if (option_value_sp
) {
486 OptionValueProperties
*ov_properties
= option_value_sp
->GetAsProperties();
488 return ov_properties
->shared_from_this();
490 return lldb::OptionValuePropertiesSP();