1//===-- Property.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/Property.h"
10
11#include "lldb/Core/UserSettingsController.h"
12#include "lldb/Interpreter/CommandInterpreter.h"
13#include "lldb/Interpreter/OptionArgParser.h"
14#include "lldb/Interpreter/OptionValues.h"
15#include "lldb/Target/Language.h"
16
17#include <memory>
18
19using namespace lldb;
20using namespace lldb_private;
21
22Property::Property(const PropertyDefinition &definition)
23    : m_name(definition.name), m_description(definition.description),
24      m_is_global(definition.global) {
25  switch (definition.type) {
26  case OptionValue::eTypeInvalid:
27  case OptionValue::eTypeProperties:
28    break;
29  case OptionValue::eTypeArch:
30    // "definition.default_uint_value" is not used
31    // "definition.default_cstr_value" as a string value that represents the
32    // default string value for the architecture/triple
33    m_value_sp =
34        std::make_shared<OptionValueArch>(definition.default_cstr_value);
35    break;
36
37  case OptionValue::eTypeArgs:
38    // "definition.default_uint_value" is always a OptionValue::Type
39    m_value_sp = std::make_shared<OptionValueArgs>();
40    break;
41
42  case OptionValue::eTypeArray:
43    // "definition.default_uint_value" is always a OptionValue::Type
44    m_value_sp =
45        std::make_shared<OptionValueArray>(OptionValue::ConvertTypeToMask(
46            (OptionValue::Type)definition.default_uint_value));
47    break;
48
49  case OptionValue::eTypeBoolean:
50    // "definition.default_uint_value" is the default boolean value if
51    // "definition.default_cstr_value" is NULL, otherwise interpret
52    // "definition.default_cstr_value" as a string value that represents the
53    // default value.
54    if (definition.default_cstr_value)
55      m_value_sp =
56          std::make_shared<OptionValueBoolean>(OptionArgParser::ToBoolean(
57              llvm::StringRef(definition.default_cstr_value), false, nullptr));
58    else
59      m_value_sp = std::make_shared<OptionValueBoolean>(
60          definition.default_uint_value != 0);
61    break;
62
63  case OptionValue::eTypeChar: {
64    llvm::StringRef s(definition.default_cstr_value ? definition.default_cstr_value : "");
65    m_value_sp = std::make_shared<OptionValueChar>(
66        OptionArgParser::ToChar(s, '\0', nullptr));
67    break;
68  }
69  case OptionValue::eTypeDictionary:
70    // "definition.default_uint_value" is always a OptionValue::Type
71    m_value_sp = std::make_shared<OptionValueDictionary>(
72        OptionValue::ConvertTypeToMask(
73            (OptionValue::Type)definition.default_uint_value),
74        definition.enum_values);
75    break;
76
77  case OptionValue::eTypeEnum:
78    // "definition.default_uint_value" is the default enumeration value if
79    // "definition.default_cstr_value" is NULL, otherwise interpret
80    // "definition.default_cstr_value" as a string value that represents the
81    // default value.
82    {
83      OptionValueEnumeration *enum_value = new OptionValueEnumeration(
84          definition.enum_values, definition.default_uint_value);
85      m_value_sp.reset(enum_value);
86      if (definition.default_cstr_value) {
87        if (enum_value
88                ->SetValueFromString(
89                    llvm::StringRef(definition.default_cstr_value))
90                .Success()) {
91          enum_value->SetDefaultValue(enum_value->GetCurrentValue());
92          // Call Clear() since we don't want the value to appear as having
93          // been set since we called SetValueFromString() above. Clear will
94          // set the current value to the default and clear the boolean that
95          // says that the value has been set.
96          enum_value->Clear();
97        }
98      }
99    }
100    break;
101
102  case OptionValue::eTypeFileLineColumn:
103    // "definition.default_uint_value" is not used for a
104    // OptionValue::eTypeFileSpecList
105    m_value_sp = std::make_shared<OptionValueFileColonLine>();
106    break;
107
108  case OptionValue::eTypeFileSpec: {
109    // "definition.default_uint_value" represents if the
110    // "definition.default_cstr_value" should be resolved or not
111    const bool resolve = definition.default_uint_value != 0;
112    FileSpec file_spec = FileSpec(definition.default_cstr_value);
113    if (resolve)
114      FileSystem::Instance().Resolve(file_spec);
115    m_value_sp = std::make_shared<OptionValueFileSpec>(file_spec, resolve);
116    break;
117  }
118
119  case OptionValue::eTypeFileSpecList:
120    // "definition.default_uint_value" is not used for a
121    // OptionValue::eTypeFileSpecList
122    m_value_sp = std::make_shared<OptionValueFileSpecList>();
123    break;
124
125  case OptionValue::eTypeFormat:
126    // "definition.default_uint_value" is the default format enumeration value
127    // if "definition.default_cstr_value" is NULL, otherwise interpret
128    // "definition.default_cstr_value" as a string value that represents the
129    // default value.
130    {
131      Format new_format = eFormatInvalid;
132      if (definition.default_cstr_value)
133        OptionArgParser::ToFormat(definition.default_cstr_value, new_format,
134                                  nullptr);
135      else
136        new_format = (Format)definition.default_uint_value;
137      m_value_sp = std::make_shared<OptionValueFormat>(new_format);
138    }
139    break;
140
141  case OptionValue::eTypeLanguage:
142    // "definition.default_uint_value" is the default language enumeration
143    // value if "definition.default_cstr_value" is NULL, otherwise interpret
144    // "definition.default_cstr_value" as a string value that represents the
145    // default value.
146    {
147      LanguageType new_lang = eLanguageTypeUnknown;
148      if (definition.default_cstr_value)
149        Language::GetLanguageTypeFromString(
150            llvm::StringRef(definition.default_cstr_value));
151      else
152        new_lang = (LanguageType)definition.default_uint_value;
153      m_value_sp = std::make_shared<OptionValueLanguage>(new_lang);
154    }
155    break;
156
157  case OptionValue::eTypeFormatEntity:
158    // "definition.default_cstr_value" as a string value that represents the
159    // default
160    m_value_sp = std::make_shared<OptionValueFormatEntity>(
161        definition.default_cstr_value);
162    break;
163
164  case OptionValue::eTypePathMap:
165    // "definition.default_uint_value" tells us if notifications should occur
166    // for path mappings
167    m_value_sp = std::make_shared<OptionValuePathMappings>(
168        definition.default_uint_value != 0);
169    break;
170
171  case OptionValue::eTypeRegex:
172    // "definition.default_uint_value" is used to the regular expression flags
173    // "definition.default_cstr_value" the default regular expression value
174    // value.
175    m_value_sp =
176        std::make_shared<OptionValueRegex>(definition.default_cstr_value);
177    break;
178
179  case OptionValue::eTypeSInt64: {
180    // "definition.default_uint_value" is the default integer value if
181    // "definition.default_cstr_value" is NULL, otherwise interpret
182    // "definition.default_cstr_value" as a string value that represents the
183    // default value.
184    int64_t value = 0;
185    // FIXME: improve error handling for llvm::to_integer()
186    if (definition.default_cstr_value)
187      llvm::to_integer(definition.default_cstr_value, value);
188    m_value_sp = std::make_shared<OptionValueSInt64>(
189        definition.default_cstr_value ? value : definition.default_uint_value);
190    break;
191  }
192  case OptionValue::eTypeUInt64: {
193    uint64_t value = 0;
194    // FIXME: improve error handling for llvm::to_integer()
195    if (definition.default_cstr_value)
196      llvm::to_integer(definition.default_cstr_value, value);
197    // "definition.default_uint_value" is the default unsigned integer value if
198    // "definition.default_cstr_value" is NULL, otherwise interpret
199    // "definition.default_cstr_value" as a string value that represents the
200    // default value.
201    m_value_sp = std::make_shared<OptionValueUInt64>(
202        definition.default_cstr_value ? value : definition.default_uint_value);
203    break;
204  }
205  case OptionValue::eTypeUUID:
206    // "definition.default_uint_value" is not used for a OptionValue::eTypeUUID
207    // "definition.default_cstr_value" can contain a default UUID value
208    {
209      UUID uuid;
210      if (definition.default_cstr_value)
211        uuid.SetFromStringRef(definition.default_cstr_value);
212      m_value_sp = std::make_shared<OptionValueUUID>(uuid);
213    }
214    break;
215
216  case OptionValue::eTypeString:
217    // "definition.default_uint_value" can contain the string option flags
218    // OR'ed together "definition.default_cstr_value" can contain a default
219    // string value
220    {
221      OptionValueString *string_value =
222          new OptionValueString(definition.default_cstr_value);
223      if (definition.default_uint_value != 0)
224        string_value->GetOptions().Reset(definition.default_uint_value);
225      m_value_sp.reset(string_value);
226    }
227    break;
228  }
229  assert(m_value_sp && "invalid property definition");
230}
231
232Property::Property(llvm::StringRef name, llvm::StringRef desc, bool is_global,
233                   const lldb::OptionValueSP &value_sp)
234    : m_name(name), m_description(desc), m_value_sp(value_sp),
235      m_is_global(is_global) {}
236
237bool Property::DumpQualifiedName(Stream &strm) const {
238  if (!m_name.empty()) {
239    if (m_value_sp->DumpQualifiedName(strm))
240      strm.PutChar('.');
241    strm << m_name;
242    return true;
243  }
244  return false;
245}
246
247void Property::Dump(const ExecutionContext *exe_ctx, Stream &strm,
248                    uint32_t dump_mask) const {
249  if (m_value_sp) {
250    const bool dump_desc = dump_mask & OptionValue::eDumpOptionDescription;
251    const bool dump_cmd = dump_mask & OptionValue::eDumpOptionCommand;
252    const bool transparent = m_value_sp->ValueIsTransparent();
253    if (dump_cmd && !transparent)
254      strm << "settings set -f ";
255    if (dump_desc || !transparent) {
256      if ((dump_mask & OptionValue::eDumpOptionName) && !m_name.empty()) {
257        DumpQualifiedName(strm);
258        if (dump_mask & ~OptionValue::eDumpOptionName)
259          strm.PutChar(' ');
260      }
261    }
262    if (dump_desc) {
263      llvm::StringRef desc = GetDescription();
264      if (!desc.empty())
265        strm << "-- " << desc;
266
267      if (transparent && (dump_mask == (OptionValue::eDumpOptionName |
268                                        OptionValue::eDumpOptionDescription)))
269        strm.EOL();
270    }
271    m_value_sp->DumpValue(exe_ctx, strm, dump_mask);
272  }
273}
274
275void Property::DumpDescription(CommandInterpreter &interpreter, Stream &strm,
276                               uint32_t output_width,
277                               bool display_qualified_name) const {
278  if (!m_value_sp)
279    return;
280  llvm::StringRef desc = GetDescription();
281
282  if (desc.empty())
283    return;
284
285  StreamString qualified_name;
286  const OptionValueProperties *sub_properties = m_value_sp->GetAsProperties();
287  if (sub_properties) {
288    strm.EOL();
289
290    if (m_value_sp->DumpQualifiedName(qualified_name))
291      strm.Printf("'%s' variables:\n\n", qualified_name.GetData());
292    sub_properties->DumpAllDescriptions(interpreter, strm);
293  } else {
294    if (display_qualified_name) {
295      StreamString qualified_name;
296      DumpQualifiedName(qualified_name);
297      interpreter.OutputFormattedHelpText(strm, qualified_name.GetString(),
298                                          "--", desc, output_width);
299    } else {
300      interpreter.OutputFormattedHelpText(strm, m_name, "--", desc,
301                                          output_width);
302    }
303  }
304}
305
306void Property::SetValueChangedCallback(std::function<void()> callback) {
307  if (m_value_sp)
308    m_value_sp->SetValueChangedCallback(std::move(callback));
309}
310