LLDB mainline
OptionValueProperties.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
8
10
11#include "lldb/Utility/Flags.h"
12
16#include "lldb/Utility/Args.h"
17#include "lldb/Utility/Stream.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
24 : m_name(name.str()) {}
25
27 const PropertyCollectionDefinition &defs) {
28 for (const auto &definition : defs.definitions) {
29 Property property(definition);
30 assert(property.IsValid());
31 m_name_to_index.insert({property.GetName(), m_properties.size()});
32 property.GetValue()->SetParent(shared_from_this());
33 m_properties.push_back(property);
34 }
36}
37
39 assert(m_expected_path.empty() || m_expected_path == path);
40 m_expected_path = path;
41}
42
44 size_t property_idx, std::function<void()> callback) {
45 Property *property = ProtectedGetPropertyAtIndex(property_idx);
46 if (property)
47 property->SetValueChangedCallback(std::move(callback));
48}
49
50void OptionValueProperties::AppendProperty(llvm::StringRef name,
51 llvm::StringRef desc, bool is_global,
52 const OptionValueSP &value_sp) {
53 Property property(name, desc, is_global, value_sp);
54 m_name_to_index.insert({name, m_properties.size()});
55 m_properties.push_back(property);
56 value_sp->SetParent(shared_from_this());
57
58#ifndef NDEBUG
59 OptionValueProperties *properties = value_sp->GetAsProperties();
60 if (properties) {
61 assert(value_sp->GetName() == name);
62 assert(properties->VerifyPath() &&
63 "Mismatch between parents from TableGen and actual parents");
64 }
65#endif
66}
67
70 llvm::StringRef key) const {
71 auto iter = m_name_to_index.find(key);
72 if (iter == m_name_to_index.end())
73 return OptionValueSP();
74 const size_t idx = iter->second;
75 if (idx >= m_properties.size())
76 return OptionValueSP();
77 return GetPropertyAtIndex(idx, exe_ctx)->GetValue();
78}
79
82 llvm::StringRef name, Status &error) const {
83 lldb::OptionValueSP value_sp;
84 if (name.empty())
85 return OptionValueSP();
86
87 llvm::StringRef sub_name;
88 llvm::StringRef key;
89 size_t key_len = name.find_first_of(".[{");
90 if (key_len != llvm::StringRef::npos) {
91 key = name.take_front(key_len);
92 sub_name = name.drop_front(key_len);
93 } else
94 key = name;
95
96 value_sp = GetValueForKey(exe_ctx, key);
97 if (sub_name.empty() || !value_sp)
98 return value_sp;
99
100 switch (sub_name[0]) {
101 case '.': {
102 lldb::OptionValueSP return_val_sp;
103 return_val_sp =
104 value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), error);
105 if (!return_val_sp) {
106 if (Properties::IsSettingExperimental(sub_name.drop_front())) {
107 const size_t experimental_len =
109 if (sub_name[experimental_len + 1] == '.')
110 return_val_sp = value_sp->GetSubValue(
111 exe_ctx, sub_name.drop_front(experimental_len + 2), error);
112 // It isn't an error if an experimental setting is not present.
113 if (!return_val_sp)
114 error.Clear();
115 }
116 }
117 return return_val_sp;
118 }
119 case '[':
120 // Array or dictionary access for subvalues like: "[12]" -- access
121 // 12th array element "['hello']" -- dictionary access of key named hello
122 return value_sp->GetSubValue(exe_ctx, sub_name, error);
123
124 default:
125 value_sp.reset();
126 break;
127 }
128 return value_sp;
129}
130
133 llvm::StringRef name,
134 llvm::StringRef value) {
136 llvm::SmallVector<llvm::StringRef, 8> components;
137 name.split(components, '.');
138 bool name_contains_experimental = false;
139 for (const auto &part : components)
141 name_contains_experimental = true;
142
143 lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error));
144 if (value_sp)
145 error = value_sp->SetValueFromString(value, op);
146 else {
147 // Don't set an error if the path contained .experimental. - those are
148 // allowed to be missing and should silently fail.
149 if (!name_contains_experimental && error.AsCString() == nullptr) {
150 error = Status::FromErrorStringWithFormat("invalid value path '%s'",
151 name.str().c_str());
152 }
153 }
154 return error;
155}
156
157size_t OptionValueProperties::GetPropertyIndex(llvm::StringRef name) const {
158 auto iter = m_name_to_index.find(name);
159 if (iter == m_name_to_index.end())
160 return SIZE_MAX;
161 return iter->second;
162}
163
164const Property *
166 const ExecutionContext *exe_ctx) const {
167 auto iter = m_name_to_index.find(name);
168 if (iter == m_name_to_index.end())
169 return nullptr;
170 return GetPropertyAtIndex(iter->second, exe_ctx);
171}
172
174 size_t idx, const ExecutionContext *exe_ctx) const {
175 const Property *setting = GetPropertyAtIndex(idx, exe_ctx);
176 if (setting)
177 return setting->GetValue();
178 return OptionValueSP();
179}
180
183 size_t idx, const ExecutionContext *exe_ctx) const {
184 OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
185 if (value_sp)
186 return value_sp->GetAsPathMappings();
187 return nullptr;
188}
189
192 size_t idx, const ExecutionContext *exe_ctx) const {
193 OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
194 if (value_sp)
195 return value_sp->GetAsFileSpecList();
196 return nullptr;
197}
198
200 size_t idx, Args &args, const ExecutionContext *exe_ctx) const {
201 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
202 if (!property)
203 return false;
204
205 OptionValue *value = property->GetValue().get();
206 if (!value)
207 return false;
208
209 const OptionValueArgs *arguments = value->GetAsArgs();
210 if (arguments) {
211 arguments->GetArgs(args);
212 return true;
213 }
214
215 const OptionValueArray *array = value->GetAsArray();
216 if (array) {
217 array->GetArgs(args);
218 return true;
219 }
220
221 const OptionValueDictionary *dict = value->GetAsDictionary();
222 if (dict) {
223 dict->GetArgs(args);
224 return true;
225 }
226
227 return false;
228}
229
231 size_t idx, const Args &args, const ExecutionContext *exe_ctx) {
232 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
233 if (!property)
234 return false;
235
236 OptionValue *value = property->GetValue().get();
237 if (!value)
238 return false;
239
240 OptionValueArgs *arguments = value->GetAsArgs();
241 if (arguments)
242 return arguments->SetArgs(args, eVarSetOperationAssign).Success();
243
244 OptionValueArray *array = value->GetAsArray();
245 if (array)
246 return array->SetArgs(args, eVarSetOperationAssign).Success();
247
248 OptionValueDictionary *dict = value->GetAsDictionary();
249 if (dict)
250 return dict->SetArgs(args, eVarSetOperationAssign).Success();
251
252 return false;
253}
254
257 size_t idx, const ExecutionContext *exe_ctx) const {
258 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
259 if (property)
260 return property->GetValue()->GetAsDictionary();
261 return nullptr;
262}
263
266 size_t idx, const ExecutionContext *exe_ctx) const {
267 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
268 if (property) {
269 OptionValue *value = property->GetValue().get();
270 if (value)
271 return value->GetAsFileSpec();
272 }
273 return nullptr;
274}
275
277 size_t idx, const ExecutionContext *exe_ctx) const {
278 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
279 if (property) {
280 OptionValue *value = property->GetValue().get();
281 if (value)
282 return value->GetAsSInt64();
283 }
284 return nullptr;
285}
286
288 size_t idx, const ExecutionContext *exe_ctx) const {
289 const Property *property = GetPropertyAtIndex(idx, exe_ctx);
290 if (property) {
291 OptionValue *value = property->GetValue().get();
292 if (value)
293 return value->GetAsUInt64();
294 }
295 return nullptr;
296}
297
299 size_t idx, const ExecutionContext *exe_ctx) const {
300 OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
301 if (value_sp)
302 return value_sp->GetAsString();
303 return nullptr;
304}
305
307 const size_t num_properties = m_properties.size();
308 for (size_t i = 0; i < num_properties; ++i)
309 m_properties[i].GetValue()->Clear();
310}
311
315
316 // Args args(value_cstr);
317 // const size_t argc = args.GetArgumentCount();
318 switch (op) {
320 Clear();
321 break;
322
331 break;
332 }
333
334 return error;
335}
336
338 Stream &strm, uint32_t dump_mask) {
339 const size_t num_properties = m_properties.size();
340 for (size_t i = 0; i < num_properties; ++i) {
341 const Property *property = GetPropertyAtIndex(i, exe_ctx);
342 if (property) {
343 OptionValue *option_value = property->GetValue().get();
344 assert(option_value);
345 const bool transparent_value = option_value->ValueIsTransparent();
346 property->Dump(exe_ctx, strm, dump_mask);
347 if (!transparent_value)
348 strm.EOL();
349 }
350 }
351}
352
353llvm::json::Value
355 llvm::json::Object json_properties;
356 const size_t num_properties = m_properties.size();
357 for (size_t i = 0; i < num_properties; ++i) {
358 const Property *property = GetPropertyAtIndex(i, exe_ctx);
359 if (property) {
360 OptionValue *option_value = property->GetValue().get();
361 assert(option_value);
362 json_properties.try_emplace(property->GetName(),
363 option_value->ToJSON(exe_ctx));
364 }
365 }
366 return json_properties;
367}
368
370 Stream &strm,
371 llvm::StringRef property_path,
372 uint32_t dump_mask,
373 bool is_json) {
375 lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, property_path, error));
376 if (value_sp) {
377 if (!value_sp->ValueIsTransparent()) {
378 if (dump_mask & eDumpOptionName)
379 strm.PutCString(property_path);
380 if (dump_mask & ~eDumpOptionName)
381 strm.PutChar(' ');
382 }
383 if (is_json) {
384 strm.Printf(
385 "%s",
386 llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str());
387 } else
388 value_sp->DumpValue(exe_ctx, strm, dump_mask);
389 }
390 return error;
391}
392
395 auto global_props_sp = global_properties.GetValueProperties();
396 lldbassert(global_props_sp);
397
398 auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent());
399 return std::static_pointer_cast<OptionValueProperties>(copy_sp);
400}
401
404 auto copy_sp = OptionValue::DeepCopy(new_parent);
405 // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived
406 // types that override GetType returning a different value.
407 auto *props_value_ptr = static_cast<OptionValueProperties *>(copy_sp.get());
408 lldbassert(props_value_ptr);
409
410 for (auto &property : props_value_ptr->m_properties) {
411 // Duplicate any values that are not global when constructing properties
412 // from a global copy.
413 if (!property.IsGlobal()) {
414 auto value_sp = property.GetValue()->DeepCopy(copy_sp);
415 property.SetOptionValue(value_sp);
416 }
417 }
418 return copy_sp;
419}
420
421const Property *
423 llvm::StringRef name) const {
424 if (name.empty())
425 return nullptr;
426
427 const Property *property = nullptr;
428 llvm::StringRef sub_name;
429 llvm::StringRef key;
430 size_t key_len = name.find_first_of(".[{");
431
432 if (key_len != llvm::StringRef::npos) {
433 key = name.take_front(key_len);
434 sub_name = name.drop_front(key_len);
435 } else
436 key = name;
437
438 property = GetProperty(key, exe_ctx);
439 if (sub_name.empty() || !property)
440 return property;
441
442 if (sub_name[0] == '.') {
443 OptionValueProperties *sub_properties =
444 property->GetValue()->GetAsProperties();
445 if (sub_properties)
446 return sub_properties->GetPropertyAtPath(exe_ctx, sub_name.drop_front());
447 }
448 return nullptr;
449}
450
452 Stream &strm) const {
453 size_t max_name_len = 0;
454 const size_t num_properties = m_properties.size();
455 for (size_t i = 0; i < num_properties; ++i) {
456 const Property *property = ProtectedGetPropertyAtIndex(i);
457 if (property)
458 max_name_len = std::max<size_t>(property->GetName().size(), max_name_len);
459 }
460 for (size_t i = 0; i < num_properties; ++i) {
461 const Property *property = ProtectedGetPropertyAtIndex(i);
462 if (property)
463 property->DumpDescription(interpreter, strm, max_name_len, false);
464 }
465}
466
468 llvm::StringRef keyword,
469 std::vector<const Property *> &matching_properties) const {
470 const size_t num_properties = m_properties.size();
471 StreamString strm;
472 for (size_t i = 0; i < num_properties; ++i) {
473 const Property *property = ProtectedGetPropertyAtIndex(i);
474 if (property) {
475 const OptionValueProperties *properties =
476 property->GetValue()->GetAsProperties();
477 if (properties) {
478 properties->Apropos(keyword, matching_properties);
479 } else {
480 bool match = false;
481 llvm::StringRef name = property->GetName();
482 if (name.contains_insensitive(keyword))
483 match = true;
484 else {
485 llvm::StringRef desc = property->GetDescription();
486 if (desc.contains_insensitive(keyword))
487 match = true;
488 }
489 if (match) {
490 matching_properties.push_back(property);
491 }
492 }
493 }
494 }
495}
496
499 llvm::StringRef name) {
500 lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name));
501 if (option_value_sp) {
502 OptionValueProperties *ov_properties = option_value_sp->GetAsProperties();
503 if (ov_properties)
504 return ov_properties->shared_from_this();
505 }
507}
508
510 OptionValueSP parent = GetParent();
511 if (!parent) {
512 // Only the top level value should have an empty path.
513 return m_expected_path.empty();
514 }
515 OptionValueProperties *parent_properties = parent->GetAsProperties();
516 if (!parent_properties)
517 return false;
518
519 auto [prefix, expected_name] = llvm::StringRef(m_expected_path).rsplit('.');
520
521 if (expected_name.empty()) {
522 // There is no dot, so the parent should be the top-level (core properties).
523 return parent_properties->m_expected_path.empty() && GetName() == prefix;
524 }
525
526 return parent_properties->m_expected_path == prefix &&
527 GetName() == expected_name;
528}
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition LLDBAssert.h:16
A command line argument class.
Definition Args.h:33
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
size_t GetArgs(Args &args) const
Status SetArgs(const Args &args, VarSetOperationType op)
size_t GetArgs(Args &args) const
Status SetArgs(const Args &args, VarSetOperationType op)
void AppendProperty(llvm::StringRef name, llvm::StringRef desc, bool is_global, const lldb::OptionValueSP &value_sp)
Status SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op, llvm::StringRef path, llvm::StringRef value) override
OptionValueFileSpec * GetPropertyAtIndexAsOptionValueFileSpec(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
void Apropos(llvm::StringRef keyword, std::vector< const Property * > &matching_properties) const
void Initialize(const PropertyCollectionDefinition &setting_definitions)
lldb::OptionValueSP DeepCopy(const lldb::OptionValueSP &new_parent) const override
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) override
virtual void DumpAllDescriptions(CommandInterpreter &interpreter, Stream &strm) const
OptionValueFileSpecList * GetPropertyAtIndexAsOptionValueFileSpecList(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
Property * ProtectedGetPropertyAtIndex(size_t idx)
OptionValueString * GetPropertyAtIndexAsOptionValueString(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx, Stream &strm, llvm::StringRef property_path, uint32_t dump_mask, bool is_json=false)
OptionValueDictionary * GetPropertyAtIndexAsOptionValueDictionary(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
llvm::StringRef GetName() const override
static lldb::OptionValuePropertiesSP CreateLocalCopy(const Properties &global_properties)
lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx, llvm::StringRef name, Status &error) const override
llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) const override
void SetValueChangedCallback(size_t property_idx, std::function< void()> callback)
bool SetPropertyAtIndexFromArgs(size_t idx, const Args &args, const ExecutionContext *exe_ctx=nullptr)
Status SetValueFromString(llvm::StringRef value, VarSetOperationType op=eVarSetOperationAssign) override
virtual const Property * GetPropertyAtPath(const ExecutionContext *exe_ctx, llvm::StringRef property_path) const
virtual const Property * GetPropertyAtIndex(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
virtual lldb::OptionValueSP GetValueForKey(const ExecutionContext *exe_ctx, llvm::StringRef key) const
lldb::OptionValuePropertiesSP GetSubProperty(const ExecutionContext *exe_ctx, llvm::StringRef name)
virtual lldb::OptionValueSP GetPropertyValueAtIndex(size_t idx, const ExecutionContext *exe_ctx) const
OptionValueUInt64 * GetPropertyAtIndexAsOptionValueUInt64(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
OptionValuePathMappings * GetPropertyAtIndexAsOptionValuePathMappings(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
OptionValueSInt64 * GetPropertyAtIndexAsOptionValueSInt64(size_t idx, const ExecutionContext *exe_ctx=nullptr) const
virtual const Property * GetProperty(llvm::StringRef name, const ExecutionContext *exe_ctx=nullptr) const
bool GetPropertyAtIndexAsArgs(size_t idx, Args &args, const ExecutionContext *exe_ctx=nullptr) const
virtual size_t GetPropertyIndex(llvm::StringRef name) const
OptionValueDictionary * GetAsDictionary()
virtual Status SetValueFromString(llvm::StringRef value, VarSetOperationType op=eVarSetOperationAssign)
OptionValueSInt64 * GetAsSInt64()
virtual llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) const =0
virtual bool ValueIsTransparent() const
Definition OptionValue.h:85
OptionValueUInt64 * GetAsUInt64()
virtual lldb::OptionValueSP DeepCopy(const lldb::OptionValueSP &new_parent) const
lldb::OptionValueSP GetParent() const
OptionValueArgs * GetAsArgs()
OptionValueArray * GetAsArray()
OptionValueFileSpec * GetAsFileSpec()
static bool IsSettingExperimental(llvm::StringRef setting)
static llvm::StringRef GetExperimentalSettingsName()
lldb::OptionValuePropertiesSP GetValueProperties() const
const lldb::OptionValueSP & GetValue() const
Definition Property.h:48
bool IsValid() const
Definition Property.h:54
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
bool Success() const
Test for success condition.
Definition Status.cpp:303
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:65
size_t PutChar(char ch)
Definition Stream.cpp:131
size_t EOL()
Output and End of Line character to the stream.
Definition Stream.cpp:155
A class that represents a running process on the host machine.
VarSetOperationType
Settable state variable types.
std::shared_ptr< lldb_private::OptionValueProperties > OptionValuePropertiesSP
std::shared_ptr< lldb_private::OptionValue > OptionValueSP
llvm::ArrayRef< PropertyDefinition > definitions
Definition Property.h:34