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