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