Path: blob/main/contrib/llvm-project/lldb/source/Interpreter/OptionValueArray.cpp
39587 views
//===-- OptionValueArray.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/OptionValueArray.h"910#include "lldb/Utility/Args.h"11#include "lldb/Utility/Stream.h"1213using namespace lldb;14using namespace lldb_private;1516void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,17uint32_t dump_mask) {18const Type array_element_type = ConvertTypeMaskToType(m_type_mask);19if (dump_mask & eDumpOptionType) {20if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))21strm.Printf("(%s of %ss)", GetTypeAsCString(),22GetBuiltinTypeAsCString(array_element_type));23else24strm.Printf("(%s)", GetTypeAsCString());25}26if (dump_mask & eDumpOptionValue) {27const bool one_line = dump_mask & eDumpOptionCommand;28const uint32_t size = m_values.size();29if (dump_mask & eDumpOptionType)30strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");31if (!one_line)32strm.IndentMore();33for (uint32_t i = 0; i < size; ++i) {34if (!one_line) {35strm.Indent();36strm.Printf("[%u]: ", i);37}38const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;39switch (array_element_type) {40default:41case eTypeArray:42case eTypeDictionary:43case eTypeProperties:44case eTypeFileSpecList:45case eTypePathMap:46m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);47break;4849case eTypeBoolean:50case eTypeChar:51case eTypeEnum:52case eTypeFileSpec:53case eTypeFileLineColumn:54case eTypeFormat:55case eTypeSInt64:56case eTypeString:57case eTypeUInt64:58case eTypeUUID:59// No need to show the type for dictionaries of simple items60m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) |61extra_dump_options);62break;63}6465if (!one_line) {66if (i < (size - 1))67strm.EOL();68} else {69strm << ' ';70}71}72if (!one_line)73strm.IndentLess();74}75}7677llvm::json::Value OptionValueArray::ToJSON(const ExecutionContext *exe_ctx) {78llvm::json::Array json_array;79const uint32_t size = m_values.size();80for (uint32_t i = 0; i < size; ++i)81json_array.emplace_back(m_values[i]->ToJSON(exe_ctx));82return json_array;83}8485Status OptionValueArray::SetValueFromString(llvm::StringRef value,86VarSetOperationType op) {87Args args(value.str());88Status error = SetArgs(args, op);89if (error.Success())90NotifyValueChanged();91return error;92}9394lldb::OptionValueSP95OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx,96llvm::StringRef name, Status &error) const {97if (name.empty() || name.front() != '[') {98error.SetErrorStringWithFormat(99"invalid value path '%s', %s values only support '[<index>]' subvalues "100"where <index> is a positive or negative array index",101name.str().c_str(), GetTypeAsCString());102return nullptr;103}104105name = name.drop_front();106llvm::StringRef index, sub_value;107std::tie(index, sub_value) = name.split(']');108if (index.size() == name.size()) {109// Couldn't find a closing bracket110return nullptr;111}112113const size_t array_count = m_values.size();114int32_t idx = 0;115if (index.getAsInteger(0, idx))116return nullptr;117118uint32_t new_idx = UINT32_MAX;119if (idx < 0) {120// Access from the end of the array if the index is negative121new_idx = array_count - idx;122} else {123// Just a standard index124new_idx = idx;125}126127if (new_idx < array_count) {128if (m_values[new_idx]) {129if (!sub_value.empty())130return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, error);131else132return m_values[new_idx];133}134} else {135if (array_count == 0)136error.SetErrorStringWithFormat(137"index %i is not valid for an empty array", idx);138else if (idx > 0)139error.SetErrorStringWithFormat(140"index %i out of range, valid values are 0 through %" PRIu64,141idx, (uint64_t)(array_count - 1));142else143error.SetErrorStringWithFormat("negative index %i out of range, "144"valid values are -1 through "145"-%" PRIu64,146idx, (uint64_t)array_count);147}148return OptionValueSP();149}150151size_t OptionValueArray::GetArgs(Args &args) const {152args.Clear();153const uint32_t size = m_values.size();154for (uint32_t i = 0; i < size; ++i) {155auto string_value = m_values[i]->GetValueAs<llvm::StringRef>();156if (string_value)157args.AppendArgument(*string_value);158}159160return args.GetArgumentCount();161}162163Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {164Status error;165const size_t argc = args.GetArgumentCount();166switch (op) {167case eVarSetOperationInvalid:168error.SetErrorString("unsupported operation");169break;170171case eVarSetOperationInsertBefore:172case eVarSetOperationInsertAfter:173if (argc > 1) {174uint32_t idx;175const uint32_t count = GetSize();176if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {177error.SetErrorStringWithFormat(178"invalid insert array index %s, index must be 0 through %u",179args.GetArgumentAtIndex(0), count);180} else {181if (op == eVarSetOperationInsertAfter)182++idx;183for (size_t i = 1; i < argc; ++i, ++idx) {184lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(185args.GetArgumentAtIndex(i), m_type_mask, error));186if (value_sp) {187if (error.Fail())188return error;189if (idx >= m_values.size())190m_values.push_back(value_sp);191else192m_values.insert(m_values.begin() + idx, value_sp);193} else {194error.SetErrorString(195"array of complex types must subclass OptionValueArray");196return error;197}198}199}200} else {201error.SetErrorString("insert operation takes an array index followed by "202"one or more values");203}204break;205206case eVarSetOperationRemove:207if (argc > 0) {208const uint32_t size = m_values.size();209std::vector<int> remove_indexes;210bool all_indexes_valid = true;211size_t i;212for (i = 0; i < argc; ++i) {213size_t idx;214if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx >= size) {215all_indexes_valid = false;216break;217} else218remove_indexes.push_back(idx);219}220221if (all_indexes_valid) {222size_t num_remove_indexes = remove_indexes.size();223if (num_remove_indexes) {224// Sort and then erase in reverse so indexes are always valid225if (num_remove_indexes > 1) {226llvm::sort(remove_indexes);227for (std::vector<int>::const_reverse_iterator228pos = remove_indexes.rbegin(),229end = remove_indexes.rend();230pos != end; ++pos) {231m_values.erase(m_values.begin() + *pos);232}233} else {234// Only one index235m_values.erase(m_values.begin() + remove_indexes.front());236}237}238} else {239error.SetErrorStringWithFormat(240"invalid array index '%s', aborting remove operation",241args.GetArgumentAtIndex(i));242}243} else {244error.SetErrorString("remove operation takes one or more array indices");245}246break;247248case eVarSetOperationClear:249Clear();250break;251252case eVarSetOperationReplace:253if (argc > 1) {254uint32_t idx;255const uint32_t count = GetSize();256if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {257error.SetErrorStringWithFormat(258"invalid replace array index %s, index must be 0 through %u",259args.GetArgumentAtIndex(0), count);260} else {261for (size_t i = 1; i < argc; ++i, ++idx) {262lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(263args.GetArgumentAtIndex(i), m_type_mask, error));264if (value_sp) {265if (error.Fail())266return error;267if (idx < count)268m_values[idx] = value_sp;269else270m_values.push_back(value_sp);271} else {272error.SetErrorString(273"array of complex types must subclass OptionValueArray");274return error;275}276}277}278} else {279error.SetErrorString("replace operation takes an array index followed by "280"one or more values");281}282break;283284case eVarSetOperationAssign:285m_values.clear();286// Fall through to append case287[[fallthrough]];288case eVarSetOperationAppend:289for (size_t i = 0; i < argc; ++i) {290lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(291args.GetArgumentAtIndex(i), m_type_mask, error));292if (value_sp) {293if (error.Fail())294return error;295m_value_was_set = true;296AppendValue(value_sp);297} else {298error.SetErrorString(299"array of complex types must subclass OptionValueArray");300}301}302break;303}304return error;305}306307OptionValueSP308OptionValueArray::DeepCopy(const OptionValueSP &new_parent) const {309auto copy_sp = OptionValue::DeepCopy(new_parent);310// copy_sp->GetAsArray cannot be used here as it doesn't work for derived311// types that override GetType returning a different value.312auto *array_value_ptr = static_cast<OptionValueArray *>(copy_sp.get());313lldbassert(array_value_ptr);314315for (auto &value : array_value_ptr->m_values)316value = value->DeepCopy(copy_sp);317318return copy_sp;319}320321322