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 24 OptionValueProperties::OptionValueProperties(const ConstString &name) 25 : OptionValue(), m_name(name), m_properties(), m_name_to_index() {} 26 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 48 size_t OptionValueProperties::GetNumProperties() const { 49 return m_properties.size(); 50 } 51 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 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 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 101 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 112 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 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 223 OptionValueProperties::GetPropertyIndex(const ConstString &name) const { 224 return m_name_to_index.Find(name, SIZE_MAX); 225 } 226 227 const Property * 228 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 236 const Property *OptionValueProperties::GetPropertyAtIndex( 237 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 238 return ProtectedGetPropertyAtIndex(idx); 239 } 240 241 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 * 250 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 * 259 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 267 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 * 276 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 284 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 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 322 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 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 * 347 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 355 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 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 * 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 * 390 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 401 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 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 * 425 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 436 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 447 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 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 469 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 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 492 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 500 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 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 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 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 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 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 590 lldb::OptionValueSP OptionValueProperties::DeepCopy() const { 591 llvm_unreachable("this shouldn't happen"); 592 } 593 594 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 623 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 639 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 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