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