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.
ValueIsTransparent()83   virtual bool ValueIsTransparent() const {
84     return GetType() == eTypeProperties;
85   }
86 
GetTypeAsCString()87   virtual const char *GetTypeAsCString() const {
88     return GetBuiltinTypeAsCString(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.
ToJSON(const ExecutionContext * exe_ctx)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
GetSubValue(const ExecutionContext * exe_ctx,llvm::StringRef name,Status & error)119   virtual lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx,
120                                           llvm::StringRef name,
121                                           Status &error) const {
122     error.SetErrorStringWithFormatv("'{0}' is not a valid subvalue", 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 
IsAggregateValue()130   virtual bool IsAggregateValue() const { return false; }
131 
GetName()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
GetTypeAsMask()138   uint32_t GetTypeAsMask() { return 1u << GetType(); }
139 
ConvertTypeToMask(OptionValue::Type type)140   static uint32_t ConvertTypeToMask(OptionValue::Type type) {
141     return 1u << type;
142   }
143 
ConvertTypeMaskToType(uint32_t type_mask)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 
OptionWasSet()253   bool OptionWasSet() const { return m_value_was_set; }
254 
SetOptionWasSet()255   void SetOptionWasSet() { m_value_was_set = true; }
256 
SetParent(const lldb::OptionValueSP & parent_sp)257   void SetParent(const lldb::OptionValueSP &parent_sp) {
258     m_parent_wp = parent_sp;
259   }
260 
GetParent()261   lldb::OptionValueSP GetParent() const { return m_parent_wp.lock(); }
262 
SetValueChangedCallback(std::function<void ()> callback)263   void SetValueChangedCallback(std::function<void()> callback) {
264     m_callback = std::move(callback);
265   }
266 
NotifyValueChanged()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>
GetValueAs()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>
GetValueAs()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 
SetValueAs(bool v)312   bool SetValueAs(bool v) { return SetBooleanValue(v); }
313 
SetValueAs(char v)314   bool SetValueAs(char v) { return SetCharValue(v); }
315 
SetValueAs(uint64_t v)316   bool SetValueAs(uint64_t v) { return SetUInt64Value(v); }
317 
SetValueAs(int64_t v)318   bool SetValueAs(int64_t v) { return SetSInt64Value(v); }
319 
SetValueAs(UUID v)320   bool SetValueAs(UUID v) { return SetUUIDValue(v); }
321 
SetValueAs(llvm::StringRef v)322   bool SetValueAs(llvm::StringRef v) { return SetStringValue(v); }
323 
SetValueAs(lldb::LanguageType v)324   bool SetValueAs(lldb::LanguageType v) { return SetLanguageValue(v); }
325 
SetValueAs(lldb::Format v)326   bool SetValueAs(lldb::Format v) { return SetFormatValue(v); }
327 
SetValueAs(FileSpec v)328   bool SetValueAs(FileSpec v) { return SetFileSpecValue(v); }
329 
SetValueAs(ArchSpec v)330   bool SetValueAs(ArchSpec v) { return SetArchSpecValue(v); }
331 
332   template <typename T, std::enable_if_t<std::is_enum_v<T>, bool> = true>
SetValueAs(T t)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