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 } 677