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