diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp new file mode 100644 index 000000000000..8719a2b63656 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp @@ -0,0 +1,491 @@ +//===-- OptionValueProperties.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/OptionValueProperties.h" + +#include "lldb/Utility/Flags.h" + +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Interpreter/OptionValues.h" +#include "lldb/Interpreter/Property.h" +#include "lldb/Utility/Args.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StringList.h" + +using namespace lldb; +using namespace lldb_private; + +OptionValueProperties::OptionValueProperties(llvm::StringRef name) + : m_name(name.str()) {} + +void OptionValueProperties::Initialize(const PropertyDefinitions &defs) { + for (const auto &definition : defs) { + Property property(definition); + assert(property.IsValid()); + m_name_to_index.insert({property.GetName(), m_properties.size()}); + property.GetValue()->SetParent(shared_from_this()); + m_properties.push_back(property); + } +} + +void OptionValueProperties::SetValueChangedCallback( + size_t property_idx, std::function<void()> callback) { + Property *property = ProtectedGetPropertyAtIndex(property_idx); + if (property) + property->SetValueChangedCallback(std::move(callback)); +} + +void OptionValueProperties::AppendProperty(llvm::StringRef name, + llvm::StringRef desc, bool is_global, + const OptionValueSP &value_sp) { + Property property(name, desc, is_global, value_sp); + m_name_to_index.insert({name, m_properties.size()}); + m_properties.push_back(property); + value_sp->SetParent(shared_from_this()); +} + +lldb::OptionValueSP +OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx, + llvm::StringRef key) const { + auto iter = m_name_to_index.find(key); + if (iter == m_name_to_index.end()) + return OptionValueSP(); + const size_t idx = iter->second; + if (idx >= m_properties.size()) + return OptionValueSP(); + return GetPropertyAtIndex(idx, exe_ctx)->GetValue(); +} + +lldb::OptionValueSP +OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx, + llvm::StringRef name, Status &error) const { + lldb::OptionValueSP value_sp; + if (name.empty()) + return OptionValueSP(); + + llvm::StringRef sub_name; + llvm::StringRef key; + size_t key_len = name.find_first_of(".[{"); + if (key_len != llvm::StringRef::npos) { + key = name.take_front(key_len); + sub_name = name.drop_front(key_len); + } else + key = name; + + value_sp = GetValueForKey(exe_ctx, key); + if (sub_name.empty() || !value_sp) + return value_sp; + + switch (sub_name[0]) { + case '.': { + lldb::OptionValueSP return_val_sp; + return_val_sp = + value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), error); + if (!return_val_sp) { + if (Properties::IsSettingExperimental(sub_name.drop_front())) { + const size_t experimental_len = + Properties::GetExperimentalSettingsName().size(); + if (sub_name[experimental_len + 1] == '.') + return_val_sp = value_sp->GetSubValue( + exe_ctx, sub_name.drop_front(experimental_len + 2), error); + // It isn't an error if an experimental setting is not present. + if (!return_val_sp) + error.Clear(); + } + } + return return_val_sp; + } + case '[': + // Array or dictionary access for subvalues like: "[12]" -- access + // 12th array element "['hello']" -- dictionary access of key named hello + return value_sp->GetSubValue(exe_ctx, sub_name, error); + + default: + value_sp.reset(); + break; + } + return value_sp; +} + +Status OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx, + VarSetOperationType op, + llvm::StringRef name, + llvm::StringRef value) { + Status error; + llvm::SmallVector<llvm::StringRef, 8> components; + name.split(components, '.'); + bool name_contains_experimental = false; + for (const auto &part : components) + if (Properties::IsSettingExperimental(part)) + name_contains_experimental = true; + + lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error)); + if (value_sp) + error = value_sp->SetValueFromString(value, op); + else { + // Don't set an error if the path contained .experimental. - those are + // allowed to be missing and should silently fail. + if (!name_contains_experimental && error.AsCString() == nullptr) { + error.SetErrorStringWithFormat("invalid value path '%s'", + name.str().c_str()); + } + } + return error; +} + +size_t OptionValueProperties::GetPropertyIndex(llvm::StringRef name) const { + auto iter = m_name_to_index.find(name); + if (iter == m_name_to_index.end()) + return SIZE_MAX; + return iter->second; +} + +const Property * +OptionValueProperties::GetProperty(llvm::StringRef name, + const ExecutionContext *exe_ctx) const { + auto iter = m_name_to_index.find(name); + if (iter == m_name_to_index.end()) + return nullptr; + return GetPropertyAtIndex(iter->second, exe_ctx); +} + +lldb::OptionValueSP OptionValueProperties::GetPropertyValueAtIndex( + size_t idx, const ExecutionContext *exe_ctx) const { + const Property *setting = GetPropertyAtIndex(idx, exe_ctx); + if (setting) + return setting->GetValue(); + return OptionValueSP(); +} + +OptionValuePathMappings * +OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings( + size_t idx, const ExecutionContext *exe_ctx) const { + OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx)); + if (value_sp) + return value_sp->GetAsPathMappings(); + return nullptr; +} + +OptionValueFileSpecList * +OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList( + size_t idx, const ExecutionContext *exe_ctx) const { + OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx)); + if (value_sp) + return value_sp->GetAsFileSpecList(); + return nullptr; +} + +bool OptionValueProperties::GetPropertyAtIndexAsArgs( + size_t idx, Args &args, const ExecutionContext *exe_ctx) const { + const Property *property = GetPropertyAtIndex(idx, exe_ctx); + if (!property) + return false; + + OptionValue *value = property->GetValue().get(); + if (!value) + return false; + + const OptionValueArgs *arguments = value->GetAsArgs(); + if (arguments) { + arguments->GetArgs(args); + return true; + } + + const OptionValueArray *array = value->GetAsArray(); + if (array) { + array->GetArgs(args); + return true; + } + + const OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) { + dict->GetArgs(args); + return true; + } + + return false; +} + +bool OptionValueProperties::SetPropertyAtIndexFromArgs( + size_t idx, const Args &args, const ExecutionContext *exe_ctx) { + const Property *property = GetPropertyAtIndex(idx, exe_ctx); + if (!property) + return false; + + OptionValue *value = property->GetValue().get(); + if (!value) + return false; + + OptionValueArgs *arguments = value->GetAsArgs(); + if (arguments) + return arguments->SetArgs(args, eVarSetOperationAssign).Success(); + + OptionValueArray *array = value->GetAsArray(); + if (array) + return array->SetArgs(args, eVarSetOperationAssign).Success(); + + OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->SetArgs(args, eVarSetOperationAssign).Success(); + + return false; +} + +OptionValueDictionary * +OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary( + size_t idx, const ExecutionContext *exe_ctx) const { + const Property *property = GetPropertyAtIndex(idx, exe_ctx); + if (property) + return property->GetValue()->GetAsDictionary(); + return nullptr; +} + +OptionValueFileSpec * +OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec( + size_t idx, const ExecutionContext *exe_ctx) const { + const Property *property = GetPropertyAtIndex(idx, exe_ctx); + if (property) { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetAsFileSpec(); + } + return nullptr; +} + +OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64( + size_t idx, const ExecutionContext *exe_ctx) const { + const Property *property = GetPropertyAtIndex(idx, exe_ctx); + if (property) { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetAsSInt64(); + } + return nullptr; +} + +OptionValueUInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64( + size_t idx, const ExecutionContext *exe_ctx) const { + const Property *property = GetPropertyAtIndex(idx, exe_ctx); + if (property) { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetAsUInt64(); + } + return nullptr; +} + +OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString( + size_t idx, const ExecutionContext *exe_ctx) const { + OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx)); + if (value_sp) + return value_sp->GetAsString(); + return nullptr; +} + +void OptionValueProperties::Clear() { + const size_t num_properties = m_properties.size(); + for (size_t i = 0; i < num_properties; ++i) + m_properties[i].GetValue()->Clear(); +} + +Status OptionValueProperties::SetValueFromString(llvm::StringRef value, + VarSetOperationType op) { + Status error; + + // Args args(value_cstr); + // const size_t argc = args.GetArgumentCount(); + switch (op) { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + case eVarSetOperationRemove: + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromString(value, op); + break; + } + + return error; +} + +void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx, + Stream &strm, uint32_t dump_mask) { + const size_t num_properties = m_properties.size(); + for (size_t i = 0; i < num_properties; ++i) { + const Property *property = GetPropertyAtIndex(i, exe_ctx); + if (property) { + OptionValue *option_value = property->GetValue().get(); + assert(option_value); + const bool transparent_value = option_value->ValueIsTransparent(); + property->Dump(exe_ctx, strm, dump_mask); + if (!transparent_value) + strm.EOL(); + } + } +} + +llvm::json::Value +OptionValueProperties::ToJSON(const ExecutionContext *exe_ctx) { + llvm::json::Object json_properties; + const size_t num_properties = m_properties.size(); + for (size_t i = 0; i < num_properties; ++i) { + const Property *property = GetPropertyAtIndex(i, exe_ctx); + if (property) { + OptionValue *option_value = property->GetValue().get(); + assert(option_value); + json_properties.try_emplace(property->GetName(), + option_value->ToJSON(exe_ctx)); + } + } + return json_properties; +} + +Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx, + Stream &strm, + llvm::StringRef property_path, + uint32_t dump_mask, + bool is_json) { + Status error; + lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, property_path, error)); + if (value_sp) { + if (!value_sp->ValueIsTransparent()) { + if (dump_mask & eDumpOptionName) + strm.PutCString(property_path); + if (dump_mask & ~eDumpOptionName) + strm.PutChar(' '); + } + if (is_json) { + strm.Printf( + "%s", + llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str()); + } else + value_sp->DumpValue(exe_ctx, strm, dump_mask); + } + return error; +} + +OptionValuePropertiesSP +OptionValueProperties::CreateLocalCopy(const Properties &global_properties) { + auto global_props_sp = global_properties.GetValueProperties(); + lldbassert(global_props_sp); + + auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent()); + return std::static_pointer_cast<OptionValueProperties>(copy_sp); +} + +OptionValueSP +OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *props_value_ptr = static_cast<OptionValueProperties *>(copy_sp.get()); + lldbassert(props_value_ptr); + + for (auto &property : props_value_ptr->m_properties) { + // Duplicate any values that are not global when constructing properties + // from a global copy. + if (!property.IsGlobal()) { + auto value_sp = property.GetValue()->DeepCopy(copy_sp); + property.SetOptionValue(value_sp); + } + } + return copy_sp; +} + +const Property * +OptionValueProperties::GetPropertyAtPath(const ExecutionContext *exe_ctx, + llvm::StringRef name) const { + if (name.empty()) + return nullptr; + + const Property *property = nullptr; + llvm::StringRef sub_name; + llvm::StringRef key; + size_t key_len = name.find_first_of(".[{"); + + if (key_len != llvm::StringRef::npos) { + key = name.take_front(key_len); + sub_name = name.drop_front(key_len); + } else + key = name; + + property = GetProperty(key, exe_ctx); + if (sub_name.empty() || !property) + return property; + + if (sub_name[0] == '.') { + OptionValueProperties *sub_properties = + property->GetValue()->GetAsProperties(); + if (sub_properties) + return sub_properties->GetPropertyAtPath(exe_ctx, sub_name.drop_front()); + } + return nullptr; +} + +void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter, + Stream &strm) const { + size_t max_name_len = 0; + const size_t num_properties = m_properties.size(); + for (size_t i = 0; i < num_properties; ++i) { + const Property *property = ProtectedGetPropertyAtIndex(i); + if (property) + max_name_len = std::max<size_t>(property->GetName().size(), max_name_len); + } + for (size_t i = 0; i < num_properties; ++i) { + const Property *property = ProtectedGetPropertyAtIndex(i); + if (property) + property->DumpDescription(interpreter, strm, max_name_len, false); + } +} + +void OptionValueProperties::Apropos( + llvm::StringRef keyword, + std::vector<const Property *> &matching_properties) const { + const size_t num_properties = m_properties.size(); + StreamString strm; + for (size_t i = 0; i < num_properties; ++i) { + const Property *property = ProtectedGetPropertyAtIndex(i); + if (property) { + const OptionValueProperties *properties = + property->GetValue()->GetAsProperties(); + if (properties) { + properties->Apropos(keyword, matching_properties); + } else { + bool match = false; + llvm::StringRef name = property->GetName(); + if (name.contains_insensitive(keyword)) + match = true; + else { + llvm::StringRef desc = property->GetDescription(); + if (desc.contains_insensitive(keyword)) + match = true; + } + if (match) { + matching_properties.push_back(property); + } + } + } + } +} + +lldb::OptionValuePropertiesSP +OptionValueProperties::GetSubProperty(const ExecutionContext *exe_ctx, + llvm::StringRef name) { + lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name)); + if (option_value_sp) { + OptionValueProperties *ov_properties = option_value_sp->GetAsProperties(); + if (ov_properties) + return ov_properties->shared_from_this(); + } + return lldb::OptionValuePropertiesSP(); +} |