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