xref: /freebsd-src/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
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 
9 #include "lldb/Interpreter/OptionValueProperties.h"
10 
11 #include "lldb/Utility/Flags.h"
12 
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"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 OptionValueProperties::OptionValueProperties(ConstString name) : m_name(name) {}
24 
25 size_t OptionValueProperties::GetNumProperties() const {
26   return m_properties.size();
27 }
28 
29 void OptionValueProperties::Initialize(const PropertyDefinitions &defs) {
30   for (const auto &definition : defs) {
31     Property property(definition);
32     assert(property.IsValid());
33     m_name_to_index.Append(ConstString(property.GetName()), m_properties.size());
34     property.GetValue()->SetParent(shared_from_this());
35     m_properties.push_back(property);
36   }
37   m_name_to_index.Sort();
38 }
39 
40 void OptionValueProperties::SetValueChangedCallback(
41     uint32_t property_idx, std::function<void()> callback) {
42   Property *property = ProtectedGetPropertyAtIndex(property_idx);
43   if (property)
44     property->SetValueChangedCallback(std::move(callback));
45 }
46 
47 void OptionValueProperties::AppendProperty(ConstString name,
48                                            ConstString desc,
49                                            bool is_global,
50                                            const OptionValueSP &value_sp) {
51   Property property(name.GetStringRef(), desc.GetStringRef(), is_global,
52                     value_sp);
53   m_name_to_index.Append(name, m_properties.size());
54   m_properties.push_back(property);
55   value_sp->SetParent(shared_from_this());
56   m_name_to_index.Sort();
57 }
58 
59 // bool
60 // OptionValueProperties::GetQualifiedName (Stream &strm)
61 //{
62 //    bool dumped_something = false;
63 ////    lldb::OptionValuePropertiesSP parent_sp(GetParent ());
64 ////    if (parent_sp)
65 ////    {
66 ////        parent_sp->GetQualifiedName (strm);
67 ////        strm.PutChar('.');
68 ////        dumped_something = true;
69 ////    }
70 //    if (m_name)
71 //    {
72 //        strm << m_name;
73 //        dumped_something = true;
74 //    }
75 //    return dumped_something;
76 //}
77 //
78 lldb::OptionValueSP
79 OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx,
80                                       ConstString key,
81                                       bool will_modify) const {
82   lldb::OptionValueSP value_sp;
83   size_t idx = m_name_to_index.Find(key, SIZE_MAX);
84   if (idx < m_properties.size())
85     value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue();
86   return value_sp;
87 }
88 
89 lldb::OptionValueSP
90 OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,
91                                    llvm::StringRef name, bool will_modify,
92                                    Status &error) const {
93   lldb::OptionValueSP value_sp;
94   if (name.empty())
95     return OptionValueSP();
96 
97   llvm::StringRef sub_name;
98   ConstString key;
99   size_t key_len = name.find_first_of(".[{");
100   if (key_len != llvm::StringRef::npos) {
101     key.SetString(name.take_front(key_len));
102     sub_name = name.drop_front(key_len);
103   } else
104     key.SetString(name);
105 
106   value_sp = GetValueForKey(exe_ctx, key, will_modify);
107   if (sub_name.empty() || !value_sp)
108     return value_sp;
109 
110   switch (sub_name[0]) {
111   case '.': {
112     lldb::OptionValueSP return_val_sp;
113     return_val_sp =
114         value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), will_modify, error);
115     if (!return_val_sp) {
116       if (Properties::IsSettingExperimental(sub_name.drop_front())) {
117         size_t experimental_len =
118             strlen(Properties::GetExperimentalSettingsName());
119         if (sub_name[experimental_len + 1] == '.')
120           return_val_sp = value_sp->GetSubValue(
121               exe_ctx, sub_name.drop_front(experimental_len + 2), will_modify, error);
122         // It isn't an error if an experimental setting is not present.
123         if (!return_val_sp)
124           error.Clear();
125       }
126     }
127     return return_val_sp;
128   }
129   case '[':
130     // Array or dictionary access for subvalues like: "[12]"       -- access
131     // 12th array element "['hello']"  -- dictionary access of key named hello
132     return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
133 
134   default:
135     value_sp.reset();
136     break;
137   }
138   return value_sp;
139 }
140 
141 Status OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,
142                                           VarSetOperationType op,
143                                           llvm::StringRef name,
144                                           llvm::StringRef value) {
145   Status error;
146   const bool will_modify = true;
147   llvm::SmallVector<llvm::StringRef, 8> components;
148   name.split(components, '.');
149   bool name_contains_experimental = false;
150   for (const auto &part : components)
151     if (Properties::IsSettingExperimental(part))
152       name_contains_experimental = true;
153 
154   lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
155   if (value_sp)
156     error = value_sp->SetValueFromString(value, op);
157   else {
158     // Don't set an error if the path contained .experimental. - those are
159     // allowed to be missing and should silently fail.
160     if (!name_contains_experimental && error.AsCString() == nullptr) {
161       error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
162     }
163   }
164   return error;
165 }
166 
167 uint32_t
168 OptionValueProperties::GetPropertyIndex(ConstString name) const {
169   return m_name_to_index.Find(name, SIZE_MAX);
170 }
171 
172 const Property *
173 OptionValueProperties::GetProperty(const ExecutionContext *exe_ctx,
174                                    bool will_modify,
175                                    ConstString name) const {
176   return GetPropertyAtIndex(
177       exe_ctx, will_modify,
178       m_name_to_index.Find(name, SIZE_MAX));
179 }
180 
181 const Property *OptionValueProperties::GetPropertyAtIndex(
182     const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const {
183   return ProtectedGetPropertyAtIndex(idx);
184 }
185 
186 lldb::OptionValueSP OptionValueProperties::GetPropertyValueAtIndex(
187     const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const {
188   const Property *setting = GetPropertyAtIndex(exe_ctx, will_modify, idx);
189   if (setting)
190     return setting->GetValue();
191   return OptionValueSP();
192 }
193 
194 OptionValuePathMappings *
195 OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings(
196     const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const {
197   OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx));
198   if (value_sp)
199     return value_sp->GetAsPathMappings();
200   return nullptr;
201 }
202 
203 OptionValueFileSpecList *
204 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList(
205     const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const {
206   OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx));
207   if (value_sp)
208     return value_sp->GetAsFileSpecList();
209   return nullptr;
210 }
211 
212 OptionValueArch *OptionValueProperties::GetPropertyAtIndexAsOptionValueArch(
213     const ExecutionContext *exe_ctx, uint32_t idx) const {
214   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
215   if (property)
216     return property->GetValue()->GetAsArch();
217   return nullptr;
218 }
219 
220 OptionValueLanguage *
221 OptionValueProperties::GetPropertyAtIndexAsOptionValueLanguage(
222     const ExecutionContext *exe_ctx, uint32_t idx) const {
223   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
224   if (property)
225     return property->GetValue()->GetAsLanguage();
226   return nullptr;
227 }
228 
229 bool OptionValueProperties::GetPropertyAtIndexAsArgs(
230     const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const {
231   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
232   if (!property)
233     return false;
234 
235   OptionValue *value = property->GetValue().get();
236   if (!value)
237     return false;
238 
239   const OptionValueArgs *arguments = value->GetAsArgs();
240   if (arguments)
241     return arguments->GetArgs(args);
242 
243   const OptionValueArray *array = value->GetAsArray();
244   if (array)
245     return array->GetArgs(args);
246 
247   const OptionValueDictionary *dict = value->GetAsDictionary();
248   if (dict)
249     return dict->GetArgs(args);
250 
251   return false;
252 }
253 
254 bool OptionValueProperties::SetPropertyAtIndexFromArgs(
255     const ExecutionContext *exe_ctx, uint32_t idx, const Args &args) {
256   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
257   if (!property)
258     return false;
259 
260   OptionValue *value = property->GetValue().get();
261   if (!value)
262     return false;
263 
264   OptionValueArgs *arguments = value->GetAsArgs();
265   if (arguments)
266     return arguments->SetArgs(args, eVarSetOperationAssign).Success();
267 
268   OptionValueArray *array = value->GetAsArray();
269   if (array)
270     return array->SetArgs(args, eVarSetOperationAssign).Success();
271 
272   OptionValueDictionary *dict = value->GetAsDictionary();
273   if (dict)
274     return dict->SetArgs(args, eVarSetOperationAssign).Success();
275 
276   return false;
277 }
278 
279 bool OptionValueProperties::GetPropertyAtIndexAsBoolean(
280     const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const {
281   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
282   if (property) {
283     OptionValue *value = property->GetValue().get();
284     if (value)
285       return value->GetBooleanValue(fail_value);
286   }
287   return fail_value;
288 }
289 
290 bool OptionValueProperties::SetPropertyAtIndexAsBoolean(
291     const ExecutionContext *exe_ctx, uint32_t idx, bool new_value) {
292   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
293   if (property) {
294     OptionValue *value = property->GetValue().get();
295     if (value) {
296       value->SetBooleanValue(new_value);
297       return true;
298     }
299   }
300   return false;
301 }
302 
303 OptionValueDictionary *
304 OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary(
305     const ExecutionContext *exe_ctx, uint32_t idx) const {
306   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
307   if (property)
308     return property->GetValue()->GetAsDictionary();
309   return nullptr;
310 }
311 
312 int64_t OptionValueProperties::GetPropertyAtIndexAsEnumeration(
313     const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const {
314   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
315   if (property) {
316     OptionValue *value = property->GetValue().get();
317     if (value)
318       return value->GetEnumerationValue(fail_value);
319   }
320   return fail_value;
321 }
322 
323 bool OptionValueProperties::SetPropertyAtIndexAsEnumeration(
324     const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) {
325   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
326   if (property) {
327     OptionValue *value = property->GetValue().get();
328     if (value)
329       return value->SetEnumerationValue(new_value);
330   }
331   return false;
332 }
333 
334 const FormatEntity::Entry *
335 OptionValueProperties::GetPropertyAtIndexAsFormatEntity(
336     const ExecutionContext *exe_ctx, uint32_t idx) {
337   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
338   if (property) {
339     OptionValue *value = property->GetValue().get();
340     if (value)
341       return value->GetFormatEntity();
342   }
343   return nullptr;
344 }
345 
346 OptionValueFileSpec *
347 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec(
348     const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const {
349   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
350   if (property) {
351     OptionValue *value = property->GetValue().get();
352     if (value)
353       return value->GetAsFileSpec();
354   }
355   return nullptr;
356 }
357 
358 FileSpec OptionValueProperties::GetPropertyAtIndexAsFileSpec(
359     const ExecutionContext *exe_ctx, uint32_t idx) const {
360   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
361   if (property) {
362     OptionValue *value = property->GetValue().get();
363     if (value)
364       return value->GetFileSpecValue();
365   }
366   return FileSpec();
367 }
368 
369 bool OptionValueProperties::SetPropertyAtIndexAsFileSpec(
370     const ExecutionContext *exe_ctx, uint32_t idx,
371     const FileSpec &new_file_spec) {
372   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
373   if (property) {
374     OptionValue *value = property->GetValue().get();
375     if (value)
376       return value->SetFileSpecValue(new_file_spec);
377   }
378   return false;
379 }
380 
381 const RegularExpression *
382 OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex(
383     const ExecutionContext *exe_ctx, uint32_t idx) const {
384   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
385   if (property) {
386     OptionValue *value = property->GetValue().get();
387     if (value)
388       return value->GetRegexValue();
389   }
390   return nullptr;
391 }
392 
393 OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64(
394     const ExecutionContext *exe_ctx, uint32_t idx) const {
395   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
396   if (property) {
397     OptionValue *value = property->GetValue().get();
398     if (value)
399       return value->GetAsSInt64();
400   }
401   return nullptr;
402 }
403 
404 int64_t OptionValueProperties::GetPropertyAtIndexAsSInt64(
405     const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const {
406   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
407   if (property) {
408     OptionValue *value = property->GetValue().get();
409     if (value)
410       return value->GetSInt64Value(fail_value);
411   }
412   return fail_value;
413 }
414 
415 bool OptionValueProperties::SetPropertyAtIndexAsSInt64(
416     const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) {
417   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
418   if (property) {
419     OptionValue *value = property->GetValue().get();
420     if (value)
421       return value->SetSInt64Value(new_value);
422   }
423   return false;
424 }
425 
426 llvm::StringRef OptionValueProperties::GetPropertyAtIndexAsString(
427     const ExecutionContext *exe_ctx, uint32_t idx,
428     llvm::StringRef fail_value) const {
429   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
430   if (property) {
431     OptionValue *value = property->GetValue().get();
432     if (value)
433       return value->GetStringValue(fail_value);
434   }
435   return fail_value;
436 }
437 
438 bool OptionValueProperties::SetPropertyAtIndexAsString(
439     const ExecutionContext *exe_ctx, uint32_t idx, llvm::StringRef new_value) {
440   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
441   if (property) {
442     OptionValue *value = property->GetValue().get();
443     if (value)
444       return value->SetStringValue(new_value);
445   }
446   return false;
447 }
448 
449 OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString(
450     const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const {
451   OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx));
452   if (value_sp)
453     return value_sp->GetAsString();
454   return nullptr;
455 }
456 
457 uint64_t OptionValueProperties::GetPropertyAtIndexAsUInt64(
458     const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const {
459   const Property *property = GetPropertyAtIndex(exe_ctx, false, idx);
460   if (property) {
461     OptionValue *value = property->GetValue().get();
462     if (value)
463       return value->GetUInt64Value(fail_value);
464   }
465   return fail_value;
466 }
467 
468 bool OptionValueProperties::SetPropertyAtIndexAsUInt64(
469     const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value) {
470   const Property *property = GetPropertyAtIndex(exe_ctx, true, idx);
471   if (property) {
472     OptionValue *value = property->GetValue().get();
473     if (value)
474       return value->SetUInt64Value(new_value);
475   }
476   return false;
477 }
478 
479 void OptionValueProperties::Clear() {
480   const size_t num_properties = m_properties.size();
481   for (size_t i = 0; i < num_properties; ++i)
482     m_properties[i].GetValue()->Clear();
483 }
484 
485 Status OptionValueProperties::SetValueFromString(llvm::StringRef value,
486                                                  VarSetOperationType op) {
487   Status error;
488 
489   //    Args args(value_cstr);
490   //    const size_t argc = args.GetArgumentCount();
491   switch (op) {
492   case eVarSetOperationClear:
493     Clear();
494     break;
495 
496   case eVarSetOperationReplace:
497   case eVarSetOperationAssign:
498   case eVarSetOperationRemove:
499   case eVarSetOperationInsertBefore:
500   case eVarSetOperationInsertAfter:
501   case eVarSetOperationAppend:
502   case eVarSetOperationInvalid:
503     error = OptionValue::SetValueFromString(value, op);
504     break;
505   }
506 
507   return error;
508 }
509 
510 void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx,
511                                       Stream &strm, uint32_t dump_mask) {
512   const size_t num_properties = m_properties.size();
513   for (size_t i = 0; i < num_properties; ++i) {
514     const Property *property = GetPropertyAtIndex(exe_ctx, false, i);
515     if (property) {
516       OptionValue *option_value = property->GetValue().get();
517       assert(option_value);
518       const bool transparent_value = option_value->ValueIsTransparent();
519       property->Dump(exe_ctx, strm, dump_mask);
520       if (!transparent_value)
521         strm.EOL();
522     }
523   }
524 }
525 
526 Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,
527                                                 Stream &strm,
528                                                 llvm::StringRef property_path,
529                                                 uint32_t dump_mask) {
530   Status error;
531   const bool will_modify = false;
532   lldb::OptionValueSP value_sp(
533       GetSubValue(exe_ctx, property_path, will_modify, error));
534   if (value_sp) {
535     if (!value_sp->ValueIsTransparent()) {
536       if (dump_mask & eDumpOptionName)
537         strm.PutCString(property_path);
538       if (dump_mask & ~eDumpOptionName)
539         strm.PutChar(' ');
540     }
541     value_sp->DumpValue(exe_ctx, strm, dump_mask);
542   }
543   return error;
544 }
545 
546 OptionValuePropertiesSP
547 OptionValueProperties::CreateLocalCopy(const Properties &global_properties) {
548   auto global_props_sp = global_properties.GetValueProperties();
549   lldbassert(global_props_sp);
550 
551   auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent());
552   return std::static_pointer_cast<OptionValueProperties>(copy_sp);
553 }
554 
555 OptionValueSP
556 OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const {
557   auto copy_sp = OptionValue::DeepCopy(new_parent);
558   // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived
559   // types that override GetType returning a different value.
560   auto *props_value_ptr = static_cast<OptionValueProperties *>(copy_sp.get());
561   lldbassert(props_value_ptr);
562 
563   for (auto &property : props_value_ptr->m_properties) {
564     // Duplicate any values that are not global when constructing properties
565     // from a global copy.
566     if (!property.IsGlobal()) {
567       auto value_sp = property.GetValue()->DeepCopy(copy_sp);
568       property.SetOptionValue(value_sp);
569     }
570   }
571   return copy_sp;
572 }
573 
574 const Property *OptionValueProperties::GetPropertyAtPath(
575     const ExecutionContext *exe_ctx, bool will_modify, llvm::StringRef name) const {
576   const Property *property = nullptr;
577   if (name.empty())
578     return nullptr;
579   llvm::StringRef sub_name;
580   ConstString key;
581   size_t key_len = name.find_first_of(".[{");
582 
583   if (key_len != llvm::StringRef::npos) {
584     key.SetString(name.take_front(key_len));
585     sub_name = name.drop_front(key_len);
586   } else
587     key.SetString(name);
588 
589   property = GetProperty(exe_ctx, will_modify, key);
590   if (sub_name.empty() || !property)
591     return property;
592 
593   if (sub_name[0] == '.') {
594     OptionValueProperties *sub_properties =
595         property->GetValue()->GetAsProperties();
596     if (sub_properties)
597       return sub_properties->GetPropertyAtPath(exe_ctx, will_modify,
598                                                 sub_name.drop_front());
599   }
600   return nullptr;
601 }
602 
603 void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
604                                                 Stream &strm) const {
605   size_t max_name_len = 0;
606   const size_t num_properties = m_properties.size();
607   for (size_t i = 0; i < num_properties; ++i) {
608     const Property *property = ProtectedGetPropertyAtIndex(i);
609     if (property)
610       max_name_len = std::max<size_t>(property->GetName().size(), max_name_len);
611   }
612   for (size_t i = 0; i < num_properties; ++i) {
613     const Property *property = ProtectedGetPropertyAtIndex(i);
614     if (property)
615       property->DumpDescription(interpreter, strm, max_name_len, false);
616   }
617 }
618 
619 void OptionValueProperties::Apropos(
620     llvm::StringRef keyword,
621     std::vector<const Property *> &matching_properties) const {
622   const size_t num_properties = m_properties.size();
623   StreamString strm;
624   for (size_t i = 0; i < num_properties; ++i) {
625     const Property *property = ProtectedGetPropertyAtIndex(i);
626     if (property) {
627       const OptionValueProperties *properties =
628           property->GetValue()->GetAsProperties();
629       if (properties) {
630         properties->Apropos(keyword, matching_properties);
631       } else {
632         bool match = false;
633         llvm::StringRef name = property->GetName();
634         if (name.contains_insensitive(keyword))
635           match = true;
636         else {
637           llvm::StringRef desc = property->GetDescription();
638           if (desc.contains_insensitive(keyword))
639             match = true;
640         }
641         if (match) {
642           matching_properties.push_back(property);
643         }
644       }
645     }
646   }
647 }
648 
649 lldb::OptionValuePropertiesSP
650 OptionValueProperties::GetSubProperty(const ExecutionContext *exe_ctx,
651                                       ConstString name) {
652   lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name, false));
653   if (option_value_sp) {
654     OptionValueProperties *ov_properties = option_value_sp->GetAsProperties();
655     if (ov_properties)
656       return ov_properties->shared_from_this();
657   }
658   return lldb::OptionValuePropertiesSP();
659 }
660