1 //===-- OptionValueProperties.cpp --------------------------------*- C++-*-===// 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(const 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, OptionValueChangedCallback callback, void *baton) { 64 Property *property = ProtectedGetPropertyAtIndex(property_idx); 65 if (property) 66 property->SetValueChangedCallback(callback, baton); 67 } 68 69 void OptionValueProperties::AppendProperty(const ConstString &name, 70 const 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 const 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_first_of('}'); 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 208 lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error)); 209 if (value_sp) 210 error = value_sp->SetValueFromString(value, op); 211 else { 212 // Don't set an error if the path contained .experimental. - those are 213 // allowed to be missing and should silently fail. 214 if (!name_contains_experimental && error.AsCString() == nullptr) { 215 error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str()); 216 } 217 } 218 return error; 219 } 220 221 uint32_t 222 OptionValueProperties::GetPropertyIndex(const ConstString &name) const { 223 return m_name_to_index.Find(name, SIZE_MAX); 224 } 225 226 const Property * 227 OptionValueProperties::GetProperty(const ExecutionContext *exe_ctx, 228 bool will_modify, 229 const ConstString &name) const { 230 return GetPropertyAtIndex( 231 exe_ctx, will_modify, 232 m_name_to_index.Find(name, SIZE_MAX)); 233 } 234 235 const Property *OptionValueProperties::GetPropertyAtIndex( 236 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 237 return ProtectedGetPropertyAtIndex(idx); 238 } 239 240 lldb::OptionValueSP OptionValueProperties::GetPropertyValueAtIndex( 241 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 242 const Property *setting = GetPropertyAtIndex(exe_ctx, will_modify, idx); 243 if (setting) 244 return setting->GetValue(); 245 return OptionValueSP(); 246 } 247 248 OptionValuePathMappings * 249 OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings( 250 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 251 OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx)); 252 if (value_sp) 253 return value_sp->GetAsPathMappings(); 254 return nullptr; 255 } 256 257 OptionValueFileSpecList * 258 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList( 259 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 260 OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx)); 261 if (value_sp) 262 return value_sp->GetAsFileSpecList(); 263 return nullptr; 264 } 265 266 OptionValueArch *OptionValueProperties::GetPropertyAtIndexAsOptionValueArch( 267 const ExecutionContext *exe_ctx, uint32_t idx) const { 268 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 269 if (property) 270 return property->GetValue()->GetAsArch(); 271 return nullptr; 272 } 273 274 OptionValueLanguage * 275 OptionValueProperties::GetPropertyAtIndexAsOptionValueLanguage( 276 const ExecutionContext *exe_ctx, uint32_t idx) const { 277 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 278 if (property) 279 return property->GetValue()->GetAsLanguage(); 280 return nullptr; 281 } 282 283 bool OptionValueProperties::GetPropertyAtIndexAsArgs( 284 const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const { 285 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 286 if (property) { 287 OptionValue *value = property->GetValue().get(); 288 if (value) { 289 const OptionValueArray *array = value->GetAsArray(); 290 if (array) 291 return array->GetArgs(args); 292 else { 293 const OptionValueDictionary *dict = value->GetAsDictionary(); 294 if (dict) 295 return dict->GetArgs(args); 296 } 297 } 298 } 299 return false; 300 } 301 302 bool OptionValueProperties::SetPropertyAtIndexFromArgs( 303 const ExecutionContext *exe_ctx, uint32_t idx, const Args &args) { 304 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 305 if (property) { 306 OptionValue *value = property->GetValue().get(); 307 if (value) { 308 OptionValueArray *array = value->GetAsArray(); 309 if (array) 310 return array->SetArgs(args, eVarSetOperationAssign).Success(); 311 else { 312 OptionValueDictionary *dict = value->GetAsDictionary(); 313 if (dict) 314 return dict->SetArgs(args, eVarSetOperationAssign).Success(); 315 } 316 } 317 } 318 return false; 319 } 320 321 bool OptionValueProperties::GetPropertyAtIndexAsBoolean( 322 const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const { 323 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 324 if (property) { 325 OptionValue *value = property->GetValue().get(); 326 if (value) 327 return value->GetBooleanValue(fail_value); 328 } 329 return fail_value; 330 } 331 332 bool OptionValueProperties::SetPropertyAtIndexAsBoolean( 333 const ExecutionContext *exe_ctx, uint32_t idx, bool new_value) { 334 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 335 if (property) { 336 OptionValue *value = property->GetValue().get(); 337 if (value) { 338 value->SetBooleanValue(new_value); 339 return true; 340 } 341 } 342 return false; 343 } 344 345 OptionValueDictionary * 346 OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary( 347 const ExecutionContext *exe_ctx, uint32_t idx) const { 348 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 349 if (property) 350 return property->GetValue()->GetAsDictionary(); 351 return nullptr; 352 } 353 354 int64_t OptionValueProperties::GetPropertyAtIndexAsEnumeration( 355 const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const { 356 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 357 if (property) { 358 OptionValue *value = property->GetValue().get(); 359 if (value) 360 return value->GetEnumerationValue(fail_value); 361 } 362 return fail_value; 363 } 364 365 bool OptionValueProperties::SetPropertyAtIndexAsEnumeration( 366 const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) { 367 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 368 if (property) { 369 OptionValue *value = property->GetValue().get(); 370 if (value) 371 return value->SetEnumerationValue(new_value); 372 } 373 return false; 374 } 375 376 const FormatEntity::Entry * 377 OptionValueProperties::GetPropertyAtIndexAsFormatEntity( 378 const ExecutionContext *exe_ctx, uint32_t idx) { 379 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 380 if (property) { 381 OptionValue *value = property->GetValue().get(); 382 if (value) 383 return value->GetFormatEntity(); 384 } 385 return nullptr; 386 } 387 388 OptionValueFileSpec * 389 OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec( 390 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 391 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 392 if (property) { 393 OptionValue *value = property->GetValue().get(); 394 if (value) 395 return value->GetAsFileSpec(); 396 } 397 return nullptr; 398 } 399 400 FileSpec OptionValueProperties::GetPropertyAtIndexAsFileSpec( 401 const ExecutionContext *exe_ctx, uint32_t idx) const { 402 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 403 if (property) { 404 OptionValue *value = property->GetValue().get(); 405 if (value) 406 return value->GetFileSpecValue(); 407 } 408 return FileSpec(); 409 } 410 411 bool OptionValueProperties::SetPropertyAtIndexAsFileSpec( 412 const ExecutionContext *exe_ctx, uint32_t idx, 413 const FileSpec &new_file_spec) { 414 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 415 if (property) { 416 OptionValue *value = property->GetValue().get(); 417 if (value) 418 return value->SetFileSpecValue(new_file_spec); 419 } 420 return false; 421 } 422 423 const RegularExpression * 424 OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex( 425 const ExecutionContext *exe_ctx, uint32_t idx) const { 426 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 427 if (property) { 428 OptionValue *value = property->GetValue().get(); 429 if (value) 430 return value->GetRegexValue(); 431 } 432 return nullptr; 433 } 434 435 OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64( 436 const ExecutionContext *exe_ctx, uint32_t idx) const { 437 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 438 if (property) { 439 OptionValue *value = property->GetValue().get(); 440 if (value) 441 return value->GetAsSInt64(); 442 } 443 return nullptr; 444 } 445 446 int64_t OptionValueProperties::GetPropertyAtIndexAsSInt64( 447 const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const { 448 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 449 if (property) { 450 OptionValue *value = property->GetValue().get(); 451 if (value) 452 return value->GetSInt64Value(fail_value); 453 } 454 return fail_value; 455 } 456 457 bool OptionValueProperties::SetPropertyAtIndexAsSInt64( 458 const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) { 459 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 460 if (property) { 461 OptionValue *value = property->GetValue().get(); 462 if (value) 463 return value->SetSInt64Value(new_value); 464 } 465 return false; 466 } 467 468 llvm::StringRef OptionValueProperties::GetPropertyAtIndexAsString( 469 const ExecutionContext *exe_ctx, uint32_t idx, 470 llvm::StringRef fail_value) const { 471 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 472 if (property) { 473 OptionValue *value = property->GetValue().get(); 474 if (value) 475 return value->GetStringValue(fail_value); 476 } 477 return fail_value; 478 } 479 480 bool OptionValueProperties::SetPropertyAtIndexAsString( 481 const ExecutionContext *exe_ctx, uint32_t idx, llvm::StringRef new_value) { 482 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 483 if (property) { 484 OptionValue *value = property->GetValue().get(); 485 if (value) 486 return value->SetStringValue(new_value); 487 } 488 return false; 489 } 490 491 OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString( 492 const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const { 493 OptionValueSP value_sp(GetPropertyValueAtIndex(exe_ctx, will_modify, idx)); 494 if (value_sp) 495 return value_sp->GetAsString(); 496 return nullptr; 497 } 498 499 uint64_t OptionValueProperties::GetPropertyAtIndexAsUInt64( 500 const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const { 501 const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); 502 if (property) { 503 OptionValue *value = property->GetValue().get(); 504 if (value) 505 return value->GetUInt64Value(fail_value); 506 } 507 return fail_value; 508 } 509 510 bool OptionValueProperties::SetPropertyAtIndexAsUInt64( 511 const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value) { 512 const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); 513 if (property) { 514 OptionValue *value = property->GetValue().get(); 515 if (value) 516 return value->SetUInt64Value(new_value); 517 } 518 return false; 519 } 520 521 bool OptionValueProperties::Clear() { 522 const size_t num_properties = m_properties.size(); 523 for (size_t i = 0; i < num_properties; ++i) 524 m_properties[i].GetValue()->Clear(); 525 return true; 526 } 527 528 Status OptionValueProperties::SetValueFromString(llvm::StringRef value, 529 VarSetOperationType op) { 530 Status error; 531 532 // Args args(value_cstr); 533 // const size_t argc = args.GetArgumentCount(); 534 switch (op) { 535 case eVarSetOperationClear: 536 Clear(); 537 break; 538 539 case eVarSetOperationReplace: 540 case eVarSetOperationAssign: 541 case eVarSetOperationRemove: 542 case eVarSetOperationInsertBefore: 543 case eVarSetOperationInsertAfter: 544 case eVarSetOperationAppend: 545 case eVarSetOperationInvalid: 546 error = OptionValue::SetValueFromString(value, op); 547 break; 548 } 549 550 return error; 551 } 552 553 void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx, 554 Stream &strm, uint32_t dump_mask) { 555 const size_t num_properties = m_properties.size(); 556 for (size_t i = 0; i < num_properties; ++i) { 557 const Property *property = GetPropertyAtIndex(exe_ctx, false, i); 558 if (property) { 559 OptionValue *option_value = property->GetValue().get(); 560 assert(option_value); 561 const bool transparent_value = option_value->ValueIsTransparent(); 562 property->Dump(exe_ctx, strm, dump_mask); 563 if (!transparent_value) 564 strm.EOL(); 565 } 566 } 567 } 568 569 Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx, 570 Stream &strm, 571 llvm::StringRef property_path, 572 uint32_t dump_mask) { 573 Status error; 574 const bool will_modify = false; 575 lldb::OptionValueSP value_sp( 576 GetSubValue(exe_ctx, property_path, will_modify, error)); 577 if (value_sp) { 578 if (!value_sp->ValueIsTransparent()) { 579 if (dump_mask & eDumpOptionName) 580 strm.PutCString(property_path); 581 if (dump_mask & ~eDumpOptionName) 582 strm.PutChar(' '); 583 } 584 value_sp->DumpValue(exe_ctx, strm, dump_mask); 585 } 586 return error; 587 } 588 589 lldb::OptionValueSP OptionValueProperties::DeepCopy() const { 590 llvm_unreachable("this shouldn't happen"); 591 } 592 593 const Property *OptionValueProperties::GetPropertyAtPath( 594 const ExecutionContext *exe_ctx, bool will_modify, llvm::StringRef name) const { 595 const Property *property = nullptr; 596 if (name.empty()) 597 return nullptr; 598 llvm::StringRef sub_name; 599 ConstString key; 600 size_t key_len = name.find_first_of(".[{"); 601 602 if (key_len != llvm::StringRef::npos) { 603 key.SetString(name.take_front(key_len)); 604 sub_name = name.drop_front(key_len); 605 } else 606 key.SetString(name); 607 608 property = GetProperty(exe_ctx, will_modify, key); 609 if (sub_name.empty() || !property) 610 return property; 611 612 if (sub_name[0] == '.') { 613 OptionValueProperties *sub_properties = 614 property->GetValue()->GetAsProperties(); 615 if (sub_properties) 616 return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, 617 sub_name.drop_front()); 618 } 619 return nullptr; 620 } 621 622 void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter, 623 Stream &strm) const { 624 size_t max_name_len = 0; 625 const size_t num_properties = m_properties.size(); 626 for (size_t i = 0; i < num_properties; ++i) { 627 const Property *property = ProtectedGetPropertyAtIndex(i); 628 if (property) 629 max_name_len = std::max<size_t>(property->GetName().size(), max_name_len); 630 } 631 for (size_t i = 0; i < num_properties; ++i) { 632 const Property *property = ProtectedGetPropertyAtIndex(i); 633 if (property) 634 property->DumpDescription(interpreter, strm, max_name_len, false); 635 } 636 } 637 638 void OptionValueProperties::Apropos( 639 llvm::StringRef keyword, 640 std::vector<const Property *> &matching_properties) const { 641 const size_t num_properties = m_properties.size(); 642 StreamString strm; 643 for (size_t i = 0; i < num_properties; ++i) { 644 const Property *property = ProtectedGetPropertyAtIndex(i); 645 if (property) { 646 const OptionValueProperties *properties = 647 property->GetValue()->GetAsProperties(); 648 if (properties) { 649 properties->Apropos(keyword, matching_properties); 650 } else { 651 bool match = false; 652 llvm::StringRef name = property->GetName(); 653 if (name.contains_lower(keyword)) 654 match = true; 655 else { 656 llvm::StringRef desc = property->GetDescription(); 657 if (desc.contains_lower(keyword)) 658 match = true; 659 } 660 if (match) { 661 matching_properties.push_back(property); 662 } 663 } 664 } 665 } 666 } 667 668 lldb::OptionValuePropertiesSP 669 OptionValueProperties::GetSubProperty(const ExecutionContext *exe_ctx, 670 const ConstString &name) { 671 lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name, false)); 672 if (option_value_sp) { 673 OptionValueProperties *ov_properties = option_value_sp->GetAsProperties(); 674 if (ov_properties) 675 return ov_properties->shared_from_this(); 676 } 677 return lldb::OptionValuePropertiesSP(); 678 } 679