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