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 | |
19 | using namespace lldb; |
20 | using namespace lldb_private; |
21 | |
22 | Property::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>(args: 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>(args: OptionValue::ConvertTypeToMask( |
46 | type: (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>(args: OptionArgParser::ToBoolean( |
57 | s: llvm::StringRef(definition.default_cstr_value), fail_value: false, success_ptr: nullptr)); |
58 | else |
59 | m_value_sp = std::make_shared<OptionValueBoolean>( |
60 | args: 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 | args: OptionArgParser::ToChar(s, fail_value: '\0', success_ptr: 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 | args: OptionValue::ConvertTypeToMask( |
73 | type: (OptionValue::Type)definition.default_uint_value), |
74 | args: 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(p: enum_value); |
86 | if (definition.default_cstr_value) { |
87 | if (enum_value |
88 | ->SetValueFromString( |
89 | value: 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>(args&: file_spec, args: 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(s: definition.default_cstr_value, format&: new_format, |
134 | byte_size_ptr: nullptr); |
135 | else |
136 | new_format = (Format)definition.default_uint_value; |
137 | m_value_sp = std::make_shared<OptionValueFormat>(args&: 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 | string: llvm::StringRef(definition.default_cstr_value)); |
151 | else |
152 | new_lang = (LanguageType)definition.default_uint_value; |
153 | m_value_sp = std::make_shared<OptionValueLanguage>(args&: 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 | args: 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 | args: 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>(args: 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(S: definition.default_cstr_value, Num&: value); |
188 | m_value_sp = std::make_shared<OptionValueSInt64>( |
189 | args: 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(S: definition.default_cstr_value, Num&: 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 | args: 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>(args&: 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(flags: definition.default_uint_value); |
225 | m_value_sp.reset(p: string_value); |
226 | } |
227 | break; |
228 | } |
229 | assert(m_value_sp && "invalid property definition" ); |
230 | } |
231 | |
232 | Property::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 | |
237 | bool Property::DumpQualifiedName(Stream &strm) const { |
238 | if (!m_name.empty()) { |
239 | if (m_value_sp->DumpQualifiedName(strm)) |
240 | strm.PutChar(ch: '.'); |
241 | strm << m_name; |
242 | return true; |
243 | } |
244 | return false; |
245 | } |
246 | |
247 | void 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(ch: ' '); |
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 | |
275 | void 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(strm&: qualified_name)) |
291 | strm.Printf(format: "'%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(strm&: qualified_name); |
297 | interpreter.OutputFormattedHelpText(stream&: strm, command_word: qualified_name.GetString(), |
298 | separator: "--" , help_text: desc, max_word_len: output_width); |
299 | } else { |
300 | interpreter.OutputFormattedHelpText(stream&: strm, command_word: m_name, separator: "--" , help_text: desc, |
301 | max_word_len: output_width); |
302 | } |
303 | } |
304 | } |
305 | |
306 | void Property::SetValueChangedCallback(std::function<void()> callback) { |
307 | if (m_value_sp) |
308 | m_value_sp->SetValueChangedCallback(std::move(callback)); |
309 | } |
310 | |