1 | //===-- OptionValue.h -------------------------------------------*- C++ -*-===// |
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 | #ifndef LLDB_INTERPRETER_OPTIONVALUE_H |
10 | #define LLDB_INTERPRETER_OPTIONVALUE_H |
11 | |
12 | #include "lldb/Core/FormatEntity.h" |
13 | #include "lldb/Utility/ArchSpec.h" |
14 | #include "lldb/Utility/Cloneable.h" |
15 | #include "lldb/Utility/CompletionRequest.h" |
16 | #include "lldb/Utility/ConstString.h" |
17 | #include "lldb/Utility/FileSpec.h" |
18 | #include "lldb/Utility/FileSpecList.h" |
19 | #include "lldb/Utility/Status.h" |
20 | #include "lldb/Utility/StringList.h" |
21 | #include "lldb/Utility/UUID.h" |
22 | #include "lldb/lldb-defines.h" |
23 | #include "lldb/lldb-private-enumerations.h" |
24 | #include "lldb/lldb-private-interfaces.h" |
25 | #include "llvm/Support/JSON.h" |
26 | #include <mutex> |
27 | |
28 | namespace lldb_private { |
29 | |
30 | // OptionValue |
31 | class OptionValue { |
32 | public: |
33 | enum Type { |
34 | eTypeInvalid = 0, |
35 | eTypeArch, |
36 | eTypeArgs, |
37 | eTypeArray, |
38 | eTypeBoolean, |
39 | eTypeChar, |
40 | eTypeDictionary, |
41 | eTypeEnum, |
42 | eTypeFileLineColumn, |
43 | eTypeFileSpec, |
44 | eTypeFileSpecList, |
45 | eTypeFormat, |
46 | eTypeLanguage, |
47 | eTypePathMap, |
48 | eTypeProperties, |
49 | eTypeRegex, |
50 | eTypeSInt64, |
51 | eTypeString, |
52 | eTypeUInt64, |
53 | eTypeUUID, |
54 | eTypeFormatEntity |
55 | }; |
56 | |
57 | enum { |
58 | eDumpOptionName = (1u << 0), |
59 | eDumpOptionType = (1u << 1), |
60 | eDumpOptionValue = (1u << 2), |
61 | eDumpOptionDescription = (1u << 3), |
62 | eDumpOptionRaw = (1u << 4), |
63 | eDumpOptionCommand = (1u << 5), |
64 | eDumpGroupValue = (eDumpOptionName | eDumpOptionType | eDumpOptionValue), |
65 | eDumpGroupHelp = |
66 | (eDumpOptionName | eDumpOptionType | eDumpOptionDescription), |
67 | eDumpGroupExport = (eDumpOptionCommand | eDumpOptionName | eDumpOptionValue) |
68 | }; |
69 | |
70 | OptionValue() = default; |
71 | |
72 | virtual ~OptionValue() = default; |
73 | |
74 | OptionValue(const OptionValue &other); |
75 | |
76 | OptionValue& operator=(const OptionValue &other); |
77 | |
78 | // Subclasses should override these functions |
79 | virtual Type GetType() const = 0; |
80 | |
81 | // If this value is always hidden, the avoid showing any info on this value, |
82 | // just show the info for the child values. |
83 | virtual bool ValueIsTransparent() const { |
84 | return GetType() == eTypeProperties; |
85 | } |
86 | |
87 | virtual const char *GetTypeAsCString() const { |
88 | return GetBuiltinTypeAsCString(t: GetType()); |
89 | } |
90 | |
91 | static const char *GetBuiltinTypeAsCString(Type t); |
92 | |
93 | virtual void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, |
94 | uint32_t dump_mask) = 0; |
95 | |
96 | // TODO: make this function pure virtual after implementing it in all |
97 | // child classes. |
98 | virtual llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) { |
99 | // Return nullptr which will create a llvm::json::Value() that is a NULL |
100 | // value. No setting should ever really have a NULL value in JSON. This |
101 | // indicates an error occurred and if/when we add a FromJSON() it will know |
102 | // to fail if someone tries to set it with a NULL JSON value. |
103 | return nullptr; |
104 | } |
105 | |
106 | virtual Status |
107 | SetValueFromString(llvm::StringRef value, |
108 | VarSetOperationType op = eVarSetOperationAssign); |
109 | |
110 | virtual void Clear() = 0; |
111 | |
112 | virtual lldb::OptionValueSP |
113 | DeepCopy(const lldb::OptionValueSP &new_parent) const; |
114 | |
115 | virtual void AutoComplete(CommandInterpreter &interpreter, |
116 | CompletionRequest &request); |
117 | |
118 | // Subclasses can override these functions |
119 | virtual lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx, |
120 | llvm::StringRef name, |
121 | Status &error) const { |
122 | error.SetErrorStringWithFormatv(format: "'{0}' is not a valid subvalue" , args&: name); |
123 | return lldb::OptionValueSP(); |
124 | } |
125 | |
126 | virtual Status SetSubValue(const ExecutionContext *exe_ctx, |
127 | VarSetOperationType op, llvm::StringRef name, |
128 | llvm::StringRef value); |
129 | |
130 | virtual bool IsAggregateValue() const { return false; } |
131 | |
132 | virtual llvm::StringRef GetName() const { return llvm::StringRef(); } |
133 | |
134 | virtual bool DumpQualifiedName(Stream &strm) const; |
135 | |
136 | // Subclasses should NOT override these functions as they use the above |
137 | // functions to implement functionality |
138 | uint32_t GetTypeAsMask() { return 1u << GetType(); } |
139 | |
140 | static uint32_t ConvertTypeToMask(OptionValue::Type type) { |
141 | return 1u << type; |
142 | } |
143 | |
144 | static OptionValue::Type ConvertTypeMaskToType(uint32_t type_mask) { |
145 | // If only one bit is set, then return an appropriate enumeration |
146 | switch (type_mask) { |
147 | case 1u << eTypeArch: |
148 | return eTypeArch; |
149 | case 1u << eTypeArgs: |
150 | return eTypeArgs; |
151 | case 1u << eTypeArray: |
152 | return eTypeArray; |
153 | case 1u << eTypeBoolean: |
154 | return eTypeBoolean; |
155 | case 1u << eTypeChar: |
156 | return eTypeChar; |
157 | case 1u << eTypeDictionary: |
158 | return eTypeDictionary; |
159 | case 1u << eTypeEnum: |
160 | return eTypeEnum; |
161 | case 1u << eTypeFileLineColumn: |
162 | return eTypeFileLineColumn; |
163 | case 1u << eTypeFileSpec: |
164 | return eTypeFileSpec; |
165 | case 1u << eTypeFileSpecList: |
166 | return eTypeFileSpecList; |
167 | case 1u << eTypeFormat: |
168 | return eTypeFormat; |
169 | case 1u << eTypeLanguage: |
170 | return eTypeLanguage; |
171 | case 1u << eTypePathMap: |
172 | return eTypePathMap; |
173 | case 1u << eTypeProperties: |
174 | return eTypeProperties; |
175 | case 1u << eTypeRegex: |
176 | return eTypeRegex; |
177 | case 1u << eTypeSInt64: |
178 | return eTypeSInt64; |
179 | case 1u << eTypeString: |
180 | return eTypeString; |
181 | case 1u << eTypeUInt64: |
182 | return eTypeUInt64; |
183 | case 1u << eTypeUUID: |
184 | return eTypeUUID; |
185 | } |
186 | // Else return invalid |
187 | return eTypeInvalid; |
188 | } |
189 | |
190 | static lldb::OptionValueSP |
191 | CreateValueFromCStringForTypeMask(const char *value_cstr, uint32_t type_mask, |
192 | Status &error); |
193 | |
194 | OptionValueArch *GetAsArch(); |
195 | const OptionValueArch *GetAsArch() const; |
196 | |
197 | OptionValueArray *GetAsArray(); |
198 | const OptionValueArray *GetAsArray() const; |
199 | |
200 | OptionValueArgs *GetAsArgs(); |
201 | const OptionValueArgs *GetAsArgs() const; |
202 | |
203 | OptionValueBoolean *GetAsBoolean(); |
204 | const OptionValueBoolean *GetAsBoolean() const; |
205 | |
206 | OptionValueChar *GetAsChar(); |
207 | const OptionValueChar *GetAsChar() const; |
208 | |
209 | OptionValueDictionary *GetAsDictionary(); |
210 | const OptionValueDictionary *GetAsDictionary() const; |
211 | |
212 | OptionValueEnumeration *GetAsEnumeration(); |
213 | const OptionValueEnumeration *GetAsEnumeration() const; |
214 | |
215 | OptionValueFileSpec *GetAsFileSpec(); |
216 | const OptionValueFileSpec *GetAsFileSpec() const; |
217 | |
218 | OptionValueFileSpecList *GetAsFileSpecList(); |
219 | const OptionValueFileSpecList *GetAsFileSpecList() const; |
220 | |
221 | OptionValueFormat *GetAsFormat(); |
222 | const OptionValueFormat *GetAsFormat() const; |
223 | |
224 | OptionValueLanguage *GetAsLanguage(); |
225 | const OptionValueLanguage *GetAsLanguage() const; |
226 | |
227 | OptionValuePathMappings *GetAsPathMappings(); |
228 | const OptionValuePathMappings *GetAsPathMappings() const; |
229 | |
230 | OptionValueProperties *GetAsProperties(); |
231 | const OptionValueProperties *GetAsProperties() const; |
232 | |
233 | OptionValueRegex *GetAsRegex(); |
234 | const OptionValueRegex *GetAsRegex() const; |
235 | |
236 | OptionValueSInt64 *GetAsSInt64(); |
237 | const OptionValueSInt64 *GetAsSInt64() const; |
238 | |
239 | OptionValueString *GetAsString(); |
240 | const OptionValueString *GetAsString() const; |
241 | |
242 | OptionValueUInt64 *GetAsUInt64(); |
243 | const OptionValueUInt64 *GetAsUInt64() const; |
244 | |
245 | OptionValueUUID *GetAsUUID(); |
246 | const OptionValueUUID *GetAsUUID() const; |
247 | |
248 | OptionValueFormatEntity *GetAsFormatEntity(); |
249 | const OptionValueFormatEntity *GetAsFormatEntity() const; |
250 | |
251 | bool AppendFileSpecValue(FileSpec file_spec); |
252 | |
253 | bool OptionWasSet() const { return m_value_was_set; } |
254 | |
255 | void SetOptionWasSet() { m_value_was_set = true; } |
256 | |
257 | void SetParent(const lldb::OptionValueSP &parent_sp) { |
258 | m_parent_wp = parent_sp; |
259 | } |
260 | |
261 | lldb::OptionValueSP GetParent() const { return m_parent_wp.lock(); } |
262 | |
263 | void SetValueChangedCallback(std::function<void()> callback) { |
264 | m_callback = std::move(callback); |
265 | } |
266 | |
267 | void NotifyValueChanged() { |
268 | if (m_callback) |
269 | m_callback(); |
270 | } |
271 | |
272 | template <typename T, std::enable_if_t<!std::is_pointer_v<T>, bool> = true> |
273 | std::optional<T> GetValueAs() const { |
274 | if constexpr (std::is_same_v<T, uint64_t>) |
275 | return GetUInt64Value(); |
276 | if constexpr (std::is_same_v<T, int64_t>) |
277 | return GetSInt64Value(); |
278 | if constexpr (std::is_same_v<T, bool>) |
279 | return GetBooleanValue(); |
280 | if constexpr (std::is_same_v<T, char>) |
281 | return GetCharValue(); |
282 | if constexpr (std::is_same_v<T, lldb::Format>) |
283 | return GetFormatValue(); |
284 | if constexpr (std::is_same_v<T, FileSpec>) |
285 | return GetFileSpecValue(); |
286 | if constexpr (std::is_same_v<T, FileSpecList>) |
287 | return GetFileSpecListValue(); |
288 | if constexpr (std::is_same_v<T, lldb::LanguageType>) |
289 | return GetLanguageValue(); |
290 | if constexpr (std::is_same_v<T, llvm::StringRef>) |
291 | return GetStringValue(); |
292 | if constexpr (std::is_same_v<T, ArchSpec>) |
293 | return GetArchSpecValue(); |
294 | if constexpr (std::is_enum_v<T>) |
295 | if (std::optional<int64_t> value = GetEnumerationValue()) |
296 | return static_cast<T>(*value); |
297 | return {}; |
298 | } |
299 | |
300 | template <typename T, |
301 | typename U = typename std::remove_const< |
302 | typename std::remove_pointer<T>::type>::type, |
303 | std::enable_if_t<std::is_pointer_v<T>, bool> = true> |
304 | T GetValueAs() const { |
305 | if constexpr (std::is_same_v<U, FormatEntity::Entry>) |
306 | return GetFormatEntity(); |
307 | if constexpr (std::is_same_v<U, RegularExpression>) |
308 | return GetRegexValue(); |
309 | return {}; |
310 | } |
311 | |
312 | bool SetValueAs(bool v) { return SetBooleanValue(v); } |
313 | |
314 | bool SetValueAs(char v) { return SetCharValue(v); } |
315 | |
316 | bool SetValueAs(uint64_t v) { return SetUInt64Value(v); } |
317 | |
318 | bool SetValueAs(int64_t v) { return SetSInt64Value(v); } |
319 | |
320 | bool SetValueAs(UUID v) { return SetUUIDValue(v); } |
321 | |
322 | bool SetValueAs(llvm::StringRef v) { return SetStringValue(v); } |
323 | |
324 | bool SetValueAs(lldb::LanguageType v) { return SetLanguageValue(v); } |
325 | |
326 | bool SetValueAs(lldb::Format v) { return SetFormatValue(v); } |
327 | |
328 | bool SetValueAs(FileSpec v) { return SetFileSpecValue(v); } |
329 | |
330 | bool SetValueAs(ArchSpec v) { return SetArchSpecValue(v); } |
331 | |
332 | template <typename T, std::enable_if_t<std::is_enum_v<T>, bool> = true> |
333 | bool SetValueAs(T t) { |
334 | return SetEnumerationValue(t); |
335 | } |
336 | |
337 | protected: |
338 | using TopmostBase = OptionValue; |
339 | |
340 | // Must be overriden by a derived class for correct downcasting the result of |
341 | // DeepCopy to it. Inherit from Cloneable to avoid doing this manually. |
342 | virtual lldb::OptionValueSP Clone() const = 0; |
343 | |
344 | lldb::OptionValueWP m_parent_wp; |
345 | std::function<void()> m_callback; |
346 | bool m_value_was_set = false; // This can be used to see if a value has been |
347 | // set by a call to SetValueFromCString(). It is |
348 | // often handy to know if an option value was |
349 | // set from the command line or as a setting, |
350 | // versus if we just have the default value that |
351 | // was already populated in the option value. |
352 | private: |
353 | std::optional<ArchSpec> GetArchSpecValue() const; |
354 | bool SetArchSpecValue(ArchSpec arch_spec); |
355 | |
356 | std::optional<bool> GetBooleanValue() const; |
357 | bool SetBooleanValue(bool new_value); |
358 | |
359 | std::optional<char> GetCharValue() const; |
360 | bool SetCharValue(char new_value); |
361 | |
362 | std::optional<int64_t> GetEnumerationValue() const; |
363 | bool SetEnumerationValue(int64_t value); |
364 | |
365 | std::optional<FileSpec> GetFileSpecValue() const; |
366 | bool SetFileSpecValue(FileSpec file_spec); |
367 | |
368 | std::optional<FileSpecList> GetFileSpecListValue() const; |
369 | |
370 | std::optional<int64_t> GetSInt64Value() const; |
371 | bool SetSInt64Value(int64_t new_value); |
372 | |
373 | std::optional<uint64_t> GetUInt64Value() const; |
374 | bool SetUInt64Value(uint64_t new_value); |
375 | |
376 | std::optional<lldb::Format> GetFormatValue() const; |
377 | bool SetFormatValue(lldb::Format new_value); |
378 | |
379 | std::optional<lldb::LanguageType> GetLanguageValue() const; |
380 | bool SetLanguageValue(lldb::LanguageType new_language); |
381 | |
382 | std::optional<llvm::StringRef> GetStringValue() const; |
383 | bool SetStringValue(llvm::StringRef new_value); |
384 | |
385 | std::optional<UUID> GetUUIDValue() const; |
386 | bool SetUUIDValue(const UUID &uuid); |
387 | |
388 | const FormatEntity::Entry *GetFormatEntity() const; |
389 | const RegularExpression *GetRegexValue() const; |
390 | |
391 | mutable std::mutex m_mutex; |
392 | }; |
393 | |
394 | } // namespace lldb_private |
395 | |
396 | #endif // LLDB_INTERPRETER_OPTIONVALUE_H |
397 | |