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 arguments->GetArgs(args); 253 return true; 254 } 255 256 const OptionValueArray *array = value->GetAsArray(); 257 if (array) { 258 array->GetArgs(args); 259 return true; 260 } 261 262 const OptionValueDictionary *dict = value->GetAsDictionary(); 263 if (dict) { 264 dict->GetArgs(args); 265 return true; 266 } 267 268 return false; 269 } 270 271 bool OptionValueProperties::SetPropertyAtIndexFromArgs( 272 const ExecutionContext *exe_ctx, uint32_t idx, const Args &args) { 273 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 274 if (!property) 275 return false; 276 277 OptionValue *value = property->GetValue().get(); 278 if (!value) 279 return false; 280 281 OptionValueArgs *arguments = value->GetAsArgs(); 282 if (arguments) 283 return arguments->SetArgs(args, eVarSetOperationAssign).Success(); 284 285 OptionValueArray *array = value->GetAsArray(); 286 if (array) 287 return array->SetArgs(args, eVarSetOperationAssign).Success(); 288 289 OptionValueDictionary *dict = value->GetAsDictionary(); 290 if (dict) 291 return dict->SetArgs(args, eVarSetOperationAssign).Success(); 292 293 return false; 294 } 295 296 bool OptionValueProperties::GetPropertyAtIndexAsBoolean( 297 const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const { 298 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 299 if (property) { 300 OptionValue *value = property->GetValue().get(); 301 if (value) 302 return value->GetBooleanValue(fail_value); 303 } 304 return fail_value; 305 } 306 307 bool OptionValueProperties::SetPropertyAtIndexAsBoolean( 308 const ExecutionContext *exe_ctx, uint32_t idx, bool new_value) { 309 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 310 if (property) { 311 OptionValue *value = property->GetValue().get(); 312 if (value) { 313 value->SetBooleanValue(new_value); 314 return true; 315 } 316 } 317 return false; 318 } 319 320 OptionValueDictionary * 321 OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary( 322 const ExecutionContext *exe_ctx, uint32_t idx) const { 323 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 324 if (property) 325 return property->GetValue()->GetAsDictionary(); 326 return nullptr; 327 } 328 329 int64_t OptionValueProperties::GetPropertyAtIndexAsEnumeration( 330 const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const { 331 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 332 if (property) { 333 OptionValue *value = property->GetValue().get(); 334 if (value) 335 return value->GetEnumerationValue(fail_value); 336 } 337 return fail_value; 338 } 339 340 bool OptionValueProperties::SetPropertyAtIndexAsEnumeration( 341 const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) { 342 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 343 if (property) { 344 OptionValue *value = property->GetValue().get(); 345 if (value) 346 return value->SetEnumerationValue(new_value); 347 } 348 return false; 349 } 350 351 const FormatEntity::Entry * 352 OptionValueProperties::GetPropertyAtIndexAsFormatEntity( 353 const ExecutionContext *exe_ctx, uint32_t idx) { 354 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 355 if (property) { 356 OptionValue *value = property->GetValue().get(); 357 if (value) 358 return value->GetFormatEntity(); 359 } 360 return nullptr; 361 } 362 363 OptionValueFileSpec * 364 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec( 365 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 366 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 367 if (property) { 368 OptionValue *value = property->GetValue().get(); 369 if (value) 370 return value->GetAsFileSpec(); 371 } 372 return nullptr; 373 } 374 375 FileSpec OptionValueProperties::GetPropertyAtIndexAsFileSpec( 376 const ExecutionContext *exe_ctx, uint32_t idx) const { 377 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 378 if (property) { 379 OptionValue *value = property->GetValue().get(); 380 if (value) 381 return value->GetFileSpecValue(); 382 } 383 return FileSpec(); 384 } 385 386 bool OptionValueProperties::SetPropertyAtIndexAsFileSpec( 387 const ExecutionContext *exe_ctx, uint32_t idx, 388 const FileSpec &new_file_spec) { 389 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 390 if (property) { 391 OptionValue *value = property->GetValue().get(); 392 if (value) 393 return value->SetFileSpecValue(new_file_spec); 394 } 395 return false; 396 } 397 398 const RegularExpression * 399 OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex( 400 const ExecutionContext *exe_ctx, uint32_t idx) const { 401 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 402 if (property) { 403 OptionValue *value = property->GetValue().get(); 404 if (value) 405 return value->GetRegexValue(); 406 } 407 return nullptr; 408 } 409 410 OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64( 411 const ExecutionContext *exe_ctx, uint32_t idx) const { 412 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 413 if (property) { 414 OptionValue *value = property->GetValue().get(); 415 if (value) 416 return value->GetAsSInt64(); 417 } 418 return nullptr; 419 } 420 421 OptionValueUInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64( 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->GetAsUInt64(); 428 } 429 return nullptr; 430 } 431 432 int64_t OptionValueProperties::GetPropertyAtIndexAsSInt64( 433 const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) 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->GetSInt64Value(fail_value); 439 } 440 return fail_value; 441 } 442 443 bool OptionValueProperties::SetPropertyAtIndexAsSInt64( 444 const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) { 445 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 446 if (property) { 447 OptionValue *value = property->GetValue().get(); 448 if (value) 449 return value->SetSInt64Value(new_value); 450 } 451 return false; 452 } 453 454 llvm::StringRef OptionValueProperties::GetPropertyAtIndexAsString( 455 const ExecutionContext *exe_ctx, uint32_t idx, 456 llvm::StringRef fail_value) const { 457 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 458 if (property) { 459 OptionValue *value = property->GetValue().get(); 460 if (value) 461 return value->GetStringValue(fail_value); 462 } 463 return fail_value; 464 } 465 466 bool OptionValueProperties::SetPropertyAtIndexAsString( 467 const ExecutionContext *exe_ctx, uint32_t idx, llvm::StringRef new_value) { 468 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 469 if (property) { 470 OptionValue *value = property->GetValue().get(); 471 if (value) 472 return value->SetStringValue(new_value); 473 } 474 return false; 475 } 476 477 OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString( 478 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 479 OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx)); 480 if (value_sp) 481 return value_sp->GetAsString(); 482 return nullptr; 483 } 484 485 uint64_t OptionValueProperties::GetPropertyAtIndexAsUInt64( 486 const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const { 487 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 488 if (property) { 489 OptionValue *value = property->GetValue().get(); 490 if (value) 491 return value->GetUInt64Value(fail_value); 492 } 493 return fail_value; 494 } 495 496 bool OptionValueProperties::SetPropertyAtIndexAsUInt64( 497 const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value) { 498 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 499 if (property) { 500 OptionValue *value = property->GetValue().get(); 501 if (value) 502 return value->SetUInt64Value(new_value); 503 } 504 return false; 505 } 506 507 void OptionValueProperties::Clear() { 508 const size_t num_properties = m_properties.size(); 509 for (size_t i = 0; i < num_properties; ++i) 510 m_properties[i].GetValue()->Clear(); 511 } 512 513 Status OptionValueProperties::SetValueFromString(llvm::StringRef value, 514 VarSetOperationType op) { 515 Status error; 516 517 // Args args(value_cstr); 518 // const size_t argc = args.GetArgumentCount(); 519 switch (op) { 520 case eVarSetOperationClear: 521 Clear(); 522 break; 523 524 case eVarSetOperationReplace: 525 case eVarSetOperationAssign: 526 case eVarSetOperationRemove: 527 case eVarSetOperationInsertBefore: 528 case eVarSetOperationInsertAfter: 529 case eVarSetOperationAppend: 530 case eVarSetOperationInvalid: 531 error = OptionValue::SetValueFromString(value, op); 532 break; 533 } 534 535 return error; 536 } 537 538 void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx, 539 Stream &strm, uint32_t dump_mask) { 540 const size_t num_properties = m_properties.size(); 541 for (size_t i = 0; i < num_properties; ++i) { 542 const Property *property = GetPropertyAtIndex(exe_ctx, false, i); 543 if (property) { 544 OptionValue *option_value = property->GetValue().get(); 545 assert(option_value); 546 const bool transparent_value = option_value->ValueIsTransparent(); 547 property->Dump(exe_ctx, strm, dump_mask); 548 if (!transparent_value) 549 strm.EOL(); 550 } 551 } 552 } 553 554 llvm::json::Value 555 OptionValueProperties::ToJSON(const ExecutionContext *exe_ctx) { 556 llvm::json::Object json_properties; 557 const size_t num_properties = m_properties.size(); 558 for (size_t i = 0; i < num_properties; ++i) { 559 const Property *property = GetPropertyAtIndex(exe_ctx, false, i); 560 if (property) { 561 OptionValue *option_value = property->GetValue().get(); 562 assert(option_value); 563 json_properties.try_emplace(property->GetName(), 564 option_value->ToJSON(exe_ctx)); 565 } 566 } 567 return json_properties; 568 } 569 570 Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx, 571 Stream &strm, 572 llvm::StringRef property_path, 573 uint32_t dump_mask, bool is_json) { 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 if (is_json) { 586 strm.Printf("%s", llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str()); 587 } else 588 value_sp->DumpValue(exe_ctx, strm, dump_mask); 589 } 590 return error; 591 } 592 593 OptionValuePropertiesSP 594 OptionValueProperties::CreateLocalCopy(const Properties &global_properties) { 595 auto global_props_sp = global_properties.GetValueProperties(); 596 lldbassert(global_props_sp); 597 598 auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent()); 599 return std::static_pointer_cast<OptionValueProperties>(copy_sp); 600 } 601 602 OptionValueSP 603 OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const { 604 auto copy_sp = OptionValue::DeepCopy(new_parent); 605 // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived 606 // types that override GetType returning a different value. 607 auto *props_value_ptr = static_cast<OptionValueProperties *>(copy_sp.get()); 608 lldbassert(props_value_ptr); 609 610 for (auto &property : props_value_ptr->m_properties) { 611 // Duplicate any values that are not global when constructing properties 612 // from a global copy. 613 if (!property.IsGlobal()) { 614 auto value_sp = property.GetValue()->DeepCopy(copy_sp); 615 property.SetOptionValue(value_sp); 616 } 617 } 618 return copy_sp; 619 } 620 621 const Property *OptionValueProperties::GetPropertyAtPath( 622 const ExecutionContext *exe_ctx, bool will_modify, llvm::StringRef name) const { 623 const Property *property = nullptr; 624 if (name.empty()) 625 return nullptr; 626 llvm::StringRef sub_name; 627 ConstString key; 628 size_t key_len = name.find_first_of(".[{"); 629 630 if (key_len != llvm::StringRef::npos) { 631 key.SetString(name.take_front(key_len)); 632 sub_name = name.drop_front(key_len); 633 } else 634 key.SetString(name); 635 636 property = GetProperty(exe_ctx, will_modify, key); 637 if (sub_name.empty() || !property) 638 return property; 639 640 if (sub_name[0] == '.') { 641 OptionValueProperties *sub_properties = 642 property->GetValue()->GetAsProperties(); 643 if (sub_properties) 644 return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, 645 sub_name.drop_front()); 646 } 647 return nullptr; 648 } 649 650 void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter, 651 Stream &strm) const { 652 size_t max_name_len = 0; 653 const size_t num_properties = m_properties.size(); 654 for (size_t i = 0; i < num_properties; ++i) { 655 const Property *property = ProtectedGetPropertyAtIndex(i); 656 if (property) 657 max_name_len = std::max<size_t>(property->GetName().size(), max_name_len); 658 } 659 for (size_t i = 0; i < num_properties; ++i) { 660 const Property *property = ProtectedGetPropertyAtIndex(i); 661 if (property) 662 property->DumpDescription(interpreter, strm, max_name_len, false); 663 } 664 } 665 666 void OptionValueProperties::Apropos( 667 llvm::StringRef keyword, 668 std::vector<const Property *> &matching_properties) const { 669 const size_t num_properties = m_properties.size(); 670 StreamString strm; 671 for (size_t i = 0; i < num_properties; ++i) { 672 const Property *property = ProtectedGetPropertyAtIndex(i); 673 if (property) { 674 const OptionValueProperties *properties = 675 property->GetValue()->GetAsProperties(); 676 if (properties) { 677 properties->Apropos(keyword, matching_properties); 678 } else { 679 bool match = false; 680 llvm::StringRef name = property->GetName(); 681 if (name.contains_insensitive(keyword)) 682 match = true; 683 else { 684 llvm::StringRef desc = property->GetDescription(); 685 if (desc.contains_insensitive(keyword)) 686 match = true; 687 } 688 if (match) { 689 matching_properties.push_back(property); 690 } 691 } 692 } 693 } 694 } 695 696 lldb::OptionValuePropertiesSP 697 OptionValueProperties::GetSubProperty(const ExecutionContext *exe_ctx, 698 ConstString name) { 699 lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name, false)); 700 if (option_value_sp) { 701 OptionValueProperties *ov_properties = option_value_sp->GetAsProperties(); 702 if (ov_properties) 703 return ov_properties->shared_from_this(); 704 } 705 return lldb::OptionValuePropertiesSP(); 706 } 707