Path: blob/main/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp
39587 views
//===-- OptionValueProperties.cpp -----------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Interpreter/OptionValueProperties.h"910#include "lldb/Utility/Flags.h"1112#include "lldb/Core/UserSettingsController.h"13#include "lldb/Interpreter/OptionValues.h"14#include "lldb/Interpreter/Property.h"15#include "lldb/Utility/Args.h"16#include "lldb/Utility/Stream.h"17#include "lldb/Utility/StringList.h"1819using namespace lldb;20using namespace lldb_private;2122OptionValueProperties::OptionValueProperties(llvm::StringRef name)23: m_name(name.str()) {}2425void OptionValueProperties::Initialize(const PropertyDefinitions &defs) {26for (const auto &definition : defs) {27Property property(definition);28assert(property.IsValid());29m_name_to_index.insert({property.GetName(), m_properties.size()});30property.GetValue()->SetParent(shared_from_this());31m_properties.push_back(property);32}33}3435void OptionValueProperties::SetValueChangedCallback(36size_t property_idx, std::function<void()> callback) {37Property *property = ProtectedGetPropertyAtIndex(property_idx);38if (property)39property->SetValueChangedCallback(std::move(callback));40}4142void OptionValueProperties::AppendProperty(llvm::StringRef name,43llvm::StringRef desc, bool is_global,44const OptionValueSP &value_sp) {45Property property(name, desc, is_global, value_sp);46m_name_to_index.insert({name, m_properties.size()});47m_properties.push_back(property);48value_sp->SetParent(shared_from_this());49}5051lldb::OptionValueSP52OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx,53llvm::StringRef key) const {54auto iter = m_name_to_index.find(key);55if (iter == m_name_to_index.end())56return OptionValueSP();57const size_t idx = iter->second;58if (idx >= m_properties.size())59return OptionValueSP();60return GetPropertyAtIndex(idx, exe_ctx)->GetValue();61}6263lldb::OptionValueSP64OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,65llvm::StringRef name, Status &error) const {66lldb::OptionValueSP value_sp;67if (name.empty())68return OptionValueSP();6970llvm::StringRef sub_name;71llvm::StringRef key;72size_t key_len = name.find_first_of(".[{");73if (key_len != llvm::StringRef::npos) {74key = name.take_front(key_len);75sub_name = name.drop_front(key_len);76} else77key = name;7879value_sp = GetValueForKey(exe_ctx, key);80if (sub_name.empty() || !value_sp)81return value_sp;8283switch (sub_name[0]) {84case '.': {85lldb::OptionValueSP return_val_sp;86return_val_sp =87value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), error);88if (!return_val_sp) {89if (Properties::IsSettingExperimental(sub_name.drop_front())) {90const size_t experimental_len =91Properties::GetExperimentalSettingsName().size();92if (sub_name[experimental_len + 1] == '.')93return_val_sp = value_sp->GetSubValue(94exe_ctx, sub_name.drop_front(experimental_len + 2), error);95// It isn't an error if an experimental setting is not present.96if (!return_val_sp)97error.Clear();98}99}100return return_val_sp;101}102case '[':103// Array or dictionary access for subvalues like: "[12]" -- access104// 12th array element "['hello']" -- dictionary access of key named hello105return value_sp->GetSubValue(exe_ctx, sub_name, error);106107default:108value_sp.reset();109break;110}111return value_sp;112}113114Status OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,115VarSetOperationType op,116llvm::StringRef name,117llvm::StringRef value) {118Status error;119llvm::SmallVector<llvm::StringRef, 8> components;120name.split(components, '.');121bool name_contains_experimental = false;122for (const auto &part : components)123if (Properties::IsSettingExperimental(part))124name_contains_experimental = true;125126lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error));127if (value_sp)128error = value_sp->SetValueFromString(value, op);129else {130// Don't set an error if the path contained .experimental. - those are131// allowed to be missing and should silently fail.132if (!name_contains_experimental && error.AsCString() == nullptr) {133error.SetErrorStringWithFormat("invalid value path '%s'",134name.str().c_str());135}136}137return error;138}139140size_t OptionValueProperties::GetPropertyIndex(llvm::StringRef name) const {141auto iter = m_name_to_index.find(name);142if (iter == m_name_to_index.end())143return SIZE_MAX;144return iter->second;145}146147const Property *148OptionValueProperties::GetProperty(llvm::StringRef name,149const ExecutionContext *exe_ctx) const {150auto iter = m_name_to_index.find(name);151if (iter == m_name_to_index.end())152return nullptr;153return GetPropertyAtIndex(iter->second, exe_ctx);154}155156lldb::OptionValueSP OptionValueProperties::GetPropertyValueAtIndex(157size_t idx, const ExecutionContext *exe_ctx) const {158const Property *setting = GetPropertyAtIndex(idx, exe_ctx);159if (setting)160return setting->GetValue();161return OptionValueSP();162}163164OptionValuePathMappings *165OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings(166size_t idx, const ExecutionContext *exe_ctx) const {167OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));168if (value_sp)169return value_sp->GetAsPathMappings();170return nullptr;171}172173OptionValueFileSpecList *174OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList(175size_t idx, const ExecutionContext *exe_ctx) const {176OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));177if (value_sp)178return value_sp->GetAsFileSpecList();179return nullptr;180}181182bool OptionValueProperties::GetPropertyAtIndexAsArgs(183size_t idx, Args &args, const ExecutionContext *exe_ctx) const {184const Property *property = GetPropertyAtIndex(idx, exe_ctx);185if (!property)186return false;187188OptionValue *value = property->GetValue().get();189if (!value)190return false;191192const OptionValueArgs *arguments = value->GetAsArgs();193if (arguments) {194arguments->GetArgs(args);195return true;196}197198const OptionValueArray *array = value->GetAsArray();199if (array) {200array->GetArgs(args);201return true;202}203204const OptionValueDictionary *dict = value->GetAsDictionary();205if (dict) {206dict->GetArgs(args);207return true;208}209210return false;211}212213bool OptionValueProperties::SetPropertyAtIndexFromArgs(214size_t idx, const Args &args, const ExecutionContext *exe_ctx) {215const Property *property = GetPropertyAtIndex(idx, exe_ctx);216if (!property)217return false;218219OptionValue *value = property->GetValue().get();220if (!value)221return false;222223OptionValueArgs *arguments = value->GetAsArgs();224if (arguments)225return arguments->SetArgs(args, eVarSetOperationAssign).Success();226227OptionValueArray *array = value->GetAsArray();228if (array)229return array->SetArgs(args, eVarSetOperationAssign).Success();230231OptionValueDictionary *dict = value->GetAsDictionary();232if (dict)233return dict->SetArgs(args, eVarSetOperationAssign).Success();234235return false;236}237238OptionValueDictionary *239OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary(240size_t idx, const ExecutionContext *exe_ctx) const {241const Property *property = GetPropertyAtIndex(idx, exe_ctx);242if (property)243return property->GetValue()->GetAsDictionary();244return nullptr;245}246247OptionValueFileSpec *248OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec(249size_t idx, const ExecutionContext *exe_ctx) const {250const Property *property = GetPropertyAtIndex(idx, exe_ctx);251if (property) {252OptionValue *value = property->GetValue().get();253if (value)254return value->GetAsFileSpec();255}256return nullptr;257}258259OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64(260size_t idx, const ExecutionContext *exe_ctx) const {261const Property *property = GetPropertyAtIndex(idx, exe_ctx);262if (property) {263OptionValue *value = property->GetValue().get();264if (value)265return value->GetAsSInt64();266}267return nullptr;268}269270OptionValueUInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64(271size_t idx, const ExecutionContext *exe_ctx) const {272const Property *property = GetPropertyAtIndex(idx, exe_ctx);273if (property) {274OptionValue *value = property->GetValue().get();275if (value)276return value->GetAsUInt64();277}278return nullptr;279}280281OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString(282size_t idx, const ExecutionContext *exe_ctx) const {283OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));284if (value_sp)285return value_sp->GetAsString();286return nullptr;287}288289void OptionValueProperties::Clear() {290const size_t num_properties = m_properties.size();291for (size_t i = 0; i < num_properties; ++i)292m_properties[i].GetValue()->Clear();293}294295Status OptionValueProperties::SetValueFromString(llvm::StringRef value,296VarSetOperationType op) {297Status error;298299// Args args(value_cstr);300// const size_t argc = args.GetArgumentCount();301switch (op) {302case eVarSetOperationClear:303Clear();304break;305306case eVarSetOperationReplace:307case eVarSetOperationAssign:308case eVarSetOperationRemove:309case eVarSetOperationInsertBefore:310case eVarSetOperationInsertAfter:311case eVarSetOperationAppend:312case eVarSetOperationInvalid:313error = OptionValue::SetValueFromString(value, op);314break;315}316317return error;318}319320void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx,321Stream &strm, uint32_t dump_mask) {322const size_t num_properties = m_properties.size();323for (size_t i = 0; i < num_properties; ++i) {324const Property *property = GetPropertyAtIndex(i, exe_ctx);325if (property) {326OptionValue *option_value = property->GetValue().get();327assert(option_value);328const bool transparent_value = option_value->ValueIsTransparent();329property->Dump(exe_ctx, strm, dump_mask);330if (!transparent_value)331strm.EOL();332}333}334}335336llvm::json::Value337OptionValueProperties::ToJSON(const ExecutionContext *exe_ctx) {338llvm::json::Object json_properties;339const size_t num_properties = m_properties.size();340for (size_t i = 0; i < num_properties; ++i) {341const Property *property = GetPropertyAtIndex(i, exe_ctx);342if (property) {343OptionValue *option_value = property->GetValue().get();344assert(option_value);345json_properties.try_emplace(property->GetName(),346option_value->ToJSON(exe_ctx));347}348}349return json_properties;350}351352Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,353Stream &strm,354llvm::StringRef property_path,355uint32_t dump_mask,356bool is_json) {357Status error;358lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, property_path, error));359if (value_sp) {360if (!value_sp->ValueIsTransparent()) {361if (dump_mask & eDumpOptionName)362strm.PutCString(property_path);363if (dump_mask & ~eDumpOptionName)364strm.PutChar(' ');365}366if (is_json) {367strm.Printf(368"%s",369llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str());370} else371value_sp->DumpValue(exe_ctx, strm, dump_mask);372}373return error;374}375376OptionValuePropertiesSP377OptionValueProperties::CreateLocalCopy(const Properties &global_properties) {378auto global_props_sp = global_properties.GetValueProperties();379lldbassert(global_props_sp);380381auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent());382return std::static_pointer_cast<OptionValueProperties>(copy_sp);383}384385OptionValueSP386OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const {387auto copy_sp = OptionValue::DeepCopy(new_parent);388// copy_sp->GetAsProperties cannot be used here as it doesn't work for derived389// types that override GetType returning a different value.390auto *props_value_ptr = static_cast<OptionValueProperties *>(copy_sp.get());391lldbassert(props_value_ptr);392393for (auto &property : props_value_ptr->m_properties) {394// Duplicate any values that are not global when constructing properties395// from a global copy.396if (!property.IsGlobal()) {397auto value_sp = property.GetValue()->DeepCopy(copy_sp);398property.SetOptionValue(value_sp);399}400}401return copy_sp;402}403404const Property *405OptionValueProperties::GetPropertyAtPath(const ExecutionContext *exe_ctx,406llvm::StringRef name) const {407if (name.empty())408return nullptr;409410const Property *property = nullptr;411llvm::StringRef sub_name;412llvm::StringRef key;413size_t key_len = name.find_first_of(".[{");414415if (key_len != llvm::StringRef::npos) {416key = name.take_front(key_len);417sub_name = name.drop_front(key_len);418} else419key = name;420421property = GetProperty(key, exe_ctx);422if (sub_name.empty() || !property)423return property;424425if (sub_name[0] == '.') {426OptionValueProperties *sub_properties =427property->GetValue()->GetAsProperties();428if (sub_properties)429return sub_properties->GetPropertyAtPath(exe_ctx, sub_name.drop_front());430}431return nullptr;432}433434void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,435Stream &strm) const {436size_t max_name_len = 0;437const size_t num_properties = m_properties.size();438for (size_t i = 0; i < num_properties; ++i) {439const Property *property = ProtectedGetPropertyAtIndex(i);440if (property)441max_name_len = std::max<size_t>(property->GetName().size(), max_name_len);442}443for (size_t i = 0; i < num_properties; ++i) {444const Property *property = ProtectedGetPropertyAtIndex(i);445if (property)446property->DumpDescription(interpreter, strm, max_name_len, false);447}448}449450void OptionValueProperties::Apropos(451llvm::StringRef keyword,452std::vector<const Property *> &matching_properties) const {453const size_t num_properties = m_properties.size();454StreamString strm;455for (size_t i = 0; i < num_properties; ++i) {456const Property *property = ProtectedGetPropertyAtIndex(i);457if (property) {458const OptionValueProperties *properties =459property->GetValue()->GetAsProperties();460if (properties) {461properties->Apropos(keyword, matching_properties);462} else {463bool match = false;464llvm::StringRef name = property->GetName();465if (name.contains_insensitive(keyword))466match = true;467else {468llvm::StringRef desc = property->GetDescription();469if (desc.contains_insensitive(keyword))470match = true;471}472if (match) {473matching_properties.push_back(property);474}475}476}477}478}479480lldb::OptionValuePropertiesSP481OptionValueProperties::GetSubProperty(const ExecutionContext *exe_ctx,482llvm::StringRef name) {483lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name));484if (option_value_sp) {485OptionValueProperties *ov_properties = option_value_sp->GetAsProperties();486if (ov_properties)487return ov_properties->shared_from_this();488}489return lldb::OptionValuePropertiesSP();490}491492493