[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / source / Interpreter / OptionValueProperties.cpp
blobebea94db93d4e7dd7f940f9151d04c5abca5b929
1 //===-- OptionValueProperties.cpp -----------------------------------------===//
2 //
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
6 //
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"
20 using namespace lldb;
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);
39 if (property)
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());
52 lldb::OptionValueSP
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();
64 lldb::OptionValueSP
65 OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,
66 llvm::StringRef name, Status &error) const {
67 lldb::OptionValueSP value_sp;
68 if (name.empty())
69 return OptionValueSP();
71 llvm::StringRef sub_name;
72 llvm::StringRef key;
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);
77 } else
78 key = name;
80 value_sp = GetValueForKey(exe_ctx, key);
81 if (sub_name.empty() || !value_sp)
82 return value_sp;
84 switch (sub_name[0]) {
85 case '.': {
86 lldb::OptionValueSP return_val_sp;
87 return_val_sp =
88 value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), error);
89 if (!return_val_sp) {
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.
97 if (!return_val_sp)
98 error.Clear();
101 return return_val_sp;
103 case '[':
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);
108 default:
109 value_sp.reset();
110 break;
112 return value_sp;
115 Status OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,
116 VarSetOperationType op,
117 llvm::StringRef name,
118 llvm::StringRef value) {
119 Status error;
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));
128 if (value_sp)
129 error = value_sp->SetValueFromString(value, op);
130 else {
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'",
135 name.str().c_str());
138 return error;
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())
144 return SIZE_MAX;
145 return iter->second;
148 const Property *
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())
153 return nullptr;
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);
160 if (setting)
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));
169 if (value_sp)
170 return value_sp->GetAsPathMappings();
171 return nullptr;
174 OptionValueFileSpecList *
175 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList(
176 size_t idx, const ExecutionContext *exe_ctx) const {
177 OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
178 if (value_sp)
179 return value_sp->GetAsFileSpecList();
180 return nullptr;
183 bool OptionValueProperties::GetPropertyAtIndexAsArgs(
184 size_t idx, Args &args, const ExecutionContext *exe_ctx) const {
185 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
186 if (!property)
187 return false;
189 OptionValue *value = property->GetValue().get();
190 if (!value)
191 return false;
193 const OptionValueArgs *arguments = value->GetAsArgs();
194 if (arguments) {
195 arguments->GetArgs(args);
196 return true;
199 const OptionValueArray *array = value->GetAsArray();
200 if (array) {
201 array->GetArgs(args);
202 return true;
205 const OptionValueDictionary *dict = value->GetAsDictionary();
206 if (dict) {
207 dict->GetArgs(args);
208 return true;
211 return false;
214 bool OptionValueProperties::SetPropertyAtIndexFromArgs(
215 size_t idx, const Args &args, const ExecutionContext *exe_ctx) {
216 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
217 if (!property)
218 return false;
220 OptionValue *value = property->GetValue().get();
221 if (!value)
222 return false;
224 OptionValueArgs *arguments = value->GetAsArgs();
225 if (arguments)
226 return arguments->SetArgs(args, eVarSetOperationAssign).Success();
228 OptionValueArray *array = value->GetAsArray();
229 if (array)
230 return array->SetArgs(args, eVarSetOperationAssign).Success();
232 OptionValueDictionary *dict = value->GetAsDictionary();
233 if (dict)
234 return dict->SetArgs(args, eVarSetOperationAssign).Success();
236 return false;
239 OptionValueDictionary *
240 OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary(
241 size_t idx, const ExecutionContext *exe_ctx) const {
242 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
243 if (property)
244 return property->GetValue()->GetAsDictionary();
245 return nullptr;
248 OptionValueFileSpec *
249 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec(
250 size_t idx, const ExecutionContext *exe_ctx) const {
251 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
252 if (property) {
253 OptionValue *value = property->GetValue().get();
254 if (value)
255 return value->GetAsFileSpec();
257 return nullptr;
260 OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64(
261 size_t idx, const ExecutionContext *exe_ctx) const {
262 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
263 if (property) {
264 OptionValue *value = property->GetValue().get();
265 if (value)
266 return value->GetAsSInt64();
268 return nullptr;
271 OptionValueUInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64(
272 size_t idx, const ExecutionContext *exe_ctx) const {
273 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
274 if (property) {
275 OptionValue *value = property->GetValue().get();
276 if (value)
277 return value->GetAsUInt64();
279 return nullptr;
282 OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString(
283 size_t idx, const ExecutionContext *exe_ctx) const {
284 OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
285 if (value_sp)
286 return value_sp->GetAsString();
287 return nullptr;
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) {
298 Status error;
300 // Args args(value_cstr);
301 // const size_t argc = args.GetArgumentCount();
302 switch (op) {
303 case eVarSetOperationClear:
304 Clear();
305 break;
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);
315 break;
318 return error;
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);
326 if (property) {
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)
332 strm.EOL();
337 llvm::json::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);
343 if (property) {
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,
354 Stream &strm,
355 llvm::StringRef property_path,
356 uint32_t dump_mask,
357 bool is_json) {
358 Status error;
359 lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, property_path, error));
360 if (value_sp) {
361 if (!value_sp->ValueIsTransparent()) {
362 if (dump_mask & eDumpOptionName)
363 strm.PutCString(property_path);
364 if (dump_mask & ~eDumpOptionName)
365 strm.PutChar(' ');
367 if (is_json) {
368 strm.Printf(
369 "%s",
370 llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str());
371 } else
372 value_sp->DumpValue(exe_ctx, strm, dump_mask);
374 return error;
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);
386 OptionValueSP
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);
402 return copy_sp;
405 const Property *
406 OptionValueProperties::GetPropertyAtPath(const ExecutionContext *exe_ctx,
407 llvm::StringRef name) const {
408 if (name.empty())
409 return nullptr;
411 const Property *property = nullptr;
412 llvm::StringRef sub_name;
413 llvm::StringRef key;
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);
419 } else
420 key = name;
422 property = GetProperty(key, exe_ctx);
423 if (sub_name.empty() || !property)
424 return property;
426 if (sub_name[0] == '.') {
427 OptionValueProperties *sub_properties =
428 property->GetValue()->GetAsProperties();
429 if (sub_properties)
430 return sub_properties->GetPropertyAtPath(exe_ctx, sub_name.drop_front());
432 return nullptr;
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);
441 if (property)
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);
446 if (property)
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();
455 StreamString strm;
456 for (size_t i = 0; i < num_properties; ++i) {
457 const Property *property = ProtectedGetPropertyAtIndex(i);
458 if (property) {
459 const OptionValueProperties *properties =
460 property->GetValue()->GetAsProperties();
461 if (properties) {
462 properties->Apropos(keyword, matching_properties);
463 } else {
464 bool match = false;
465 llvm::StringRef name = property->GetName();
466 if (name.contains_insensitive(keyword))
467 match = true;
468 else {
469 llvm::StringRef desc = property->GetDescription();
470 if (desc.contains_insensitive(keyword))
471 match = true;
473 if (match) {
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();
487 if (ov_properties)
488 return ov_properties->shared_from_this();
490 return lldb::OptionValuePropertiesSP();