llvm-project
320 строк · 10.1 Кб
1//===-- OptionValueArray.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/OptionValueArray.h"10
11#include "lldb/Utility/Args.h"12#include "lldb/Utility/Stream.h"13
14using namespace lldb;15using namespace lldb_private;16
17void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,18uint32_t dump_mask) {19const Type array_element_type = ConvertTypeMaskToType(m_type_mask);20if (dump_mask & eDumpOptionType) {21if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))22strm.Printf("(%s of %ss)", GetTypeAsCString(),23GetBuiltinTypeAsCString(array_element_type));24else25strm.Printf("(%s)", GetTypeAsCString());26}27if (dump_mask & eDumpOptionValue) {28const bool one_line = dump_mask & eDumpOptionCommand;29const uint32_t size = m_values.size();30if (dump_mask & eDumpOptionType)31strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");32if (!one_line)33strm.IndentMore();34for (uint32_t i = 0; i < size; ++i) {35if (!one_line) {36strm.Indent();37strm.Printf("[%u]: ", i);38}39const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;40switch (array_element_type) {41default:42case eTypeArray:43case eTypeDictionary:44case eTypeProperties:45case eTypeFileSpecList:46case eTypePathMap:47m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);48break;49
50case eTypeBoolean:51case eTypeChar:52case eTypeEnum:53case eTypeFileSpec:54case eTypeFileLineColumn:55case eTypeFormat:56case eTypeSInt64:57case eTypeString:58case eTypeUInt64:59case eTypeUUID:60// No need to show the type for dictionaries of simple items61m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) |62extra_dump_options);63break;64}65
66if (!one_line) {67if (i < (size - 1))68strm.EOL();69} else {70strm << ' ';71}72}73if (!one_line)74strm.IndentLess();75}76}
77
78llvm::json::Value OptionValueArray::ToJSON(const ExecutionContext *exe_ctx) {79llvm::json::Array json_array;80const uint32_t size = m_values.size();81for (uint32_t i = 0; i < size; ++i)82json_array.emplace_back(m_values[i]->ToJSON(exe_ctx));83return json_array;84}
85
86Status OptionValueArray::SetValueFromString(llvm::StringRef value,87VarSetOperationType op) {88Args args(value.str());89Status error = SetArgs(args, op);90if (error.Success())91NotifyValueChanged();92return error;93}
94
95lldb::OptionValueSP96OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx,97llvm::StringRef name, Status &error) const {98if (name.empty() || name.front() != '[') {99error.SetErrorStringWithFormat(100"invalid value path '%s', %s values only support '[<index>]' subvalues "101"where <index> is a positive or negative array index",102name.str().c_str(), GetTypeAsCString());103return nullptr;104}105
106name = name.drop_front();107llvm::StringRef index, sub_value;108std::tie(index, sub_value) = name.split(']');109if (index.size() == name.size()) {110// Couldn't find a closing bracket111return nullptr;112}113
114const size_t array_count = m_values.size();115int32_t idx = 0;116if (index.getAsInteger(0, idx))117return nullptr;118
119uint32_t new_idx = UINT32_MAX;120if (idx < 0) {121// Access from the end of the array if the index is negative122new_idx = array_count - idx;123} else {124// Just a standard index125new_idx = idx;126}127
128if (new_idx < array_count) {129if (m_values[new_idx]) {130if (!sub_value.empty())131return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, error);132else133return m_values[new_idx];134}135} else {136if (array_count == 0)137error.SetErrorStringWithFormat(138"index %i is not valid for an empty array", idx);139else if (idx > 0)140error.SetErrorStringWithFormat(141"index %i out of range, valid values are 0 through %" PRIu64,142idx, (uint64_t)(array_count - 1));143else144error.SetErrorStringWithFormat("negative index %i out of range, "145"valid values are -1 through "146"-%" PRIu64,147idx, (uint64_t)array_count);148}149return OptionValueSP();150}
151
152size_t OptionValueArray::GetArgs(Args &args) const {153args.Clear();154const uint32_t size = m_values.size();155for (uint32_t i = 0; i < size; ++i) {156auto string_value = m_values[i]->GetValueAs<llvm::StringRef>();157if (string_value)158args.AppendArgument(*string_value);159}160
161return args.GetArgumentCount();162}
163
164Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {165Status error;166const size_t argc = args.GetArgumentCount();167switch (op) {168case eVarSetOperationInvalid:169error.SetErrorString("unsupported operation");170break;171
172case eVarSetOperationInsertBefore:173case eVarSetOperationInsertAfter:174if (argc > 1) {175uint32_t idx;176const uint32_t count = GetSize();177if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {178error.SetErrorStringWithFormat(179"invalid insert array index %s, index must be 0 through %u",180args.GetArgumentAtIndex(0), count);181} else {182if (op == eVarSetOperationInsertAfter)183++idx;184for (size_t i = 1; i < argc; ++i, ++idx) {185lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(186args.GetArgumentAtIndex(i), m_type_mask, error));187if (value_sp) {188if (error.Fail())189return error;190if (idx >= m_values.size())191m_values.push_back(value_sp);192else193m_values.insert(m_values.begin() + idx, value_sp);194} else {195error.SetErrorString(196"array of complex types must subclass OptionValueArray");197return error;198}199}200}201} else {202error.SetErrorString("insert operation takes an array index followed by "203"one or more values");204}205break;206
207case eVarSetOperationRemove:208if (argc > 0) {209const uint32_t size = m_values.size();210std::vector<int> remove_indexes;211bool all_indexes_valid = true;212size_t i;213for (i = 0; i < argc; ++i) {214size_t idx;215if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx >= size) {216all_indexes_valid = false;217break;218} else219remove_indexes.push_back(idx);220}221
222if (all_indexes_valid) {223size_t num_remove_indexes = remove_indexes.size();224if (num_remove_indexes) {225// Sort and then erase in reverse so indexes are always valid226if (num_remove_indexes > 1) {227llvm::sort(remove_indexes);228for (std::vector<int>::const_reverse_iterator229pos = remove_indexes.rbegin(),230end = remove_indexes.rend();231pos != end; ++pos) {232m_values.erase(m_values.begin() + *pos);233}234} else {235// Only one index236m_values.erase(m_values.begin() + remove_indexes.front());237}238}239} else {240error.SetErrorStringWithFormat(241"invalid array index '%s', aborting remove operation",242args.GetArgumentAtIndex(i));243}244} else {245error.SetErrorString("remove operation takes one or more array indices");246}247break;248
249case eVarSetOperationClear:250Clear();251break;252
253case eVarSetOperationReplace:254if (argc > 1) {255uint32_t idx;256const uint32_t count = GetSize();257if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {258error.SetErrorStringWithFormat(259"invalid replace array index %s, index must be 0 through %u",260args.GetArgumentAtIndex(0), count);261} else {262for (size_t i = 1; i < argc; ++i, ++idx) {263lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(264args.GetArgumentAtIndex(i), m_type_mask, error));265if (value_sp) {266if (error.Fail())267return error;268if (idx < count)269m_values[idx] = value_sp;270else271m_values.push_back(value_sp);272} else {273error.SetErrorString(274"array of complex types must subclass OptionValueArray");275return error;276}277}278}279} else {280error.SetErrorString("replace operation takes an array index followed by "281"one or more values");282}283break;284
285case eVarSetOperationAssign:286m_values.clear();287// Fall through to append case288[[fallthrough]];289case eVarSetOperationAppend:290for (size_t i = 0; i < argc; ++i) {291lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(292args.GetArgumentAtIndex(i), m_type_mask, error));293if (value_sp) {294if (error.Fail())295return error;296m_value_was_set = true;297AppendValue(value_sp);298} else {299error.SetErrorString(300"array of complex types must subclass OptionValueArray");301}302}303break;304}305return error;306}
307
308OptionValueSP
309OptionValueArray::DeepCopy(const OptionValueSP &new_parent) const {310auto copy_sp = OptionValue::DeepCopy(new_parent);311// copy_sp->GetAsArray cannot be used here as it doesn't work for derived312// types that override GetType returning a different value.313auto *array_value_ptr = static_cast<OptionValueArray *>(copy_sp.get());314lldbassert(array_value_ptr);315
316for (auto &value : array_value_ptr->m_values)317value = value->DeepCopy(copy_sp);318
319return copy_sp;320}
321