|
11 | 11 | #include "JSONUtils.h"
|
12 | 12 | #include "RequestHandler.h"
|
13 | 13 |
|
| 14 | +using namespace lldb_dap::protocol; |
| 15 | + |
14 | 16 | namespace lldb_dap {
|
15 | 17 |
|
16 |
| -// "SetVariableRequest": { |
17 |
| -// "allOf": [ { "$ref": "#/definitions/Request" }, { |
18 |
| -// "type": "object", |
19 |
| -// "description": "setVariable request; value of command field is |
20 |
| -// 'setVariable'. Set the variable with the given name in the variable |
21 |
| -// container to a new value.", "properties": { |
22 |
| -// "command": { |
23 |
| -// "type": "string", |
24 |
| -// "enum": [ "setVariable" ] |
25 |
| -// }, |
26 |
| -// "arguments": { |
27 |
| -// "$ref": "#/definitions/SetVariableArguments" |
28 |
| -// } |
29 |
| -// }, |
30 |
| -// "required": [ "command", "arguments" ] |
31 |
| -// }] |
32 |
| -// }, |
33 |
| -// "SetVariableArguments": { |
34 |
| -// "type": "object", |
35 |
| -// "description": "Arguments for 'setVariable' request.", |
36 |
| -// "properties": { |
37 |
| -// "variablesReference": { |
38 |
| -// "type": "integer", |
39 |
| -// "description": "The reference of the variable container." |
40 |
| -// }, |
41 |
| -// "name": { |
42 |
| -// "type": "string", |
43 |
| -// "description": "The name of the variable." |
44 |
| -// }, |
45 |
| -// "value": { |
46 |
| -// "type": "string", |
47 |
| -// "description": "The value of the variable." |
48 |
| -// }, |
49 |
| -// "format": { |
50 |
| -// "$ref": "#/definitions/ValueFormat", |
51 |
| -// "description": "Specifies details on how to format the response value." |
52 |
| -// } |
53 |
| -// }, |
54 |
| -// "required": [ "variablesReference", "name", "value" ] |
55 |
| -// }, |
56 |
| -// "SetVariableResponse": { |
57 |
| -// "allOf": [ { "$ref": "#/definitions/Response" }, { |
58 |
| -// "type": "object", |
59 |
| -// "description": "Response to 'setVariable' request.", |
60 |
| -// "properties": { |
61 |
| -// "body": { |
62 |
| -// "type": "object", |
63 |
| -// "properties": { |
64 |
| -// "value": { |
65 |
| -// "type": "string", |
66 |
| -// "description": "The new value of the variable." |
67 |
| -// }, |
68 |
| -// "type": { |
69 |
| -// "type": "string", |
70 |
| -// "description": "The type of the new value. Typically shown in the |
71 |
| -// UI when hovering over the value." |
72 |
| -// }, |
73 |
| -// "variablesReference": { |
74 |
| -// "type": "number", |
75 |
| -// "description": "If variablesReference is > 0, the new value is |
76 |
| -// structured and its children can be retrieved by passing |
77 |
| -// variablesReference to the VariablesRequest." |
78 |
| -// }, |
79 |
| -// "namedVariables": { |
80 |
| -// "type": "number", |
81 |
| -// "description": "The number of named child variables. The client |
82 |
| -// can use this optional information to present the variables in a |
83 |
| -// paged UI and fetch them in chunks." |
84 |
| -// }, |
85 |
| -// "indexedVariables": { |
86 |
| -// "type": "number", |
87 |
| -// "description": "The number of indexed child variables. The client |
88 |
| -// can use this optional information to present the variables in a |
89 |
| -// paged UI and fetch them in chunks." |
90 |
| -// }, |
91 |
| -// "valueLocationReference": { |
92 |
| -// "type": "integer", |
93 |
| -// "description": "A reference that allows the client to request the |
94 |
| -// location where the new value is declared. For example, if the new |
95 |
| -// value is function pointer, the adapter may be able to look up the |
96 |
| -// function's location. This should be present only if the adapter |
97 |
| -// is likely to be able to resolve the location.\n\nThis reference |
98 |
| -// shares the same lifetime as the `variablesReference`. See |
99 |
| -// 'Lifetime of Object References' in the Overview section for |
100 |
| -// details." |
101 |
| -// } |
102 |
| -// }, |
103 |
| -// "required": [ "value" ] |
104 |
| -// } |
105 |
| -// }, |
106 |
| -// "required": [ "body" ] |
107 |
| -// }] |
108 |
| -// } |
109 |
| -void SetVariableRequestHandler::operator()( |
110 |
| - const llvm::json::Object &request) const { |
111 |
| - llvm::json::Object response; |
112 |
| - FillResponse(request, response); |
113 |
| - llvm::json::Array variables; |
114 |
| - llvm::json::Object body; |
115 |
| - const auto *arguments = request.getObject("arguments"); |
116 |
| - // This is a reference to the containing variable/scope |
117 |
| - const auto variablesReference = |
118 |
| - GetInteger<uint64_t>(arguments, "variablesReference").value_or(0); |
119 |
| - llvm::StringRef name = GetString(arguments, "name").value_or(""); |
120 |
| - |
121 |
| - const auto value = GetString(arguments, "value").value_or(""); |
122 |
| - // Set success to false just in case we don't find the variable by name |
123 |
| - response.try_emplace("success", false); |
124 |
| - |
125 |
| - lldb::SBValue variable; |
126 |
| - |
127 |
| - // The "id" is the unique integer ID that is unique within the enclosing |
128 |
| - // variablesReference. It is optionally added to any "interface Variable" |
129 |
| - // objects to uniquely identify a variable within an enclosing |
130 |
| - // variablesReference. It helps to disambiguate between two variables that |
131 |
| - // have the same name within the same scope since the "setVariables" request |
132 |
| - // only specifies the variable reference of the enclosing scope/variable, and |
133 |
| - // the name of the variable. We could have two shadowed variables with the |
134 |
| - // same name in "Locals" or "Globals". In our case the "id" absolute index |
135 |
| - // of the variable within the dap.variables list. |
136 |
| - const auto id_value = |
137 |
| - GetInteger<uint64_t>(arguments, "id").value_or(UINT64_MAX); |
138 |
| - if (id_value != UINT64_MAX) { |
139 |
| - variable = dap.variables.GetVariable(id_value); |
140 |
| - } else { |
141 |
| - variable = dap.variables.FindVariable(variablesReference, name); |
| 18 | +/// Set the variable with the given name in the variable container to a new |
| 19 | +/// value. Clients should only call this request if the corresponding capability |
| 20 | +/// `supportsSetVariable` is true. |
| 21 | +/// |
| 22 | +/// If a debug adapter implements both `setVariable` and `setExpression`, |
| 23 | +/// a client will only use `setExpression` if the variable has an evaluateName |
| 24 | +/// property. |
| 25 | +llvm::Expected<SetVariableResponseBody> |
| 26 | +SetVariableRequestHandler::Run(const SetVariableArguments &args) const { |
| 27 | + const auto args_name = llvm::StringRef(args.name); |
| 28 | + |
| 29 | + if (args.variablesReference == UINT64_MAX) { |
| 30 | + return llvm::make_error<DAPError>( |
| 31 | + llvm::formatv("invalid reference {}", args.variablesReference).str(), |
| 32 | + llvm::inconvertibleErrorCode(), |
| 33 | + /*show_user=*/false); |
142 | 34 | }
|
143 | 35 |
|
144 |
| - if (variable.IsValid()) { |
145 |
| - lldb::SBError error; |
146 |
| - bool success = variable.SetValueFromCString(value.data(), error); |
147 |
| - if (success) { |
148 |
| - VariableDescription desc(variable, |
149 |
| - dap.configuration.enableAutoVariableSummaries); |
150 |
| - EmplaceSafeString(body, "value", desc.display_value); |
151 |
| - EmplaceSafeString(body, "type", desc.display_type_name); |
152 |
| - |
153 |
| - // We don't know the index of the variable in our dap.variables |
154 |
| - // so always insert a new one to get its variablesReference. |
155 |
| - // is_permanent is false because debug console does not support |
156 |
| - // setVariable request. |
157 |
| - int64_t new_var_ref = |
158 |
| - dap.variables.InsertVariable(variable, /*is_permanent=*/false); |
159 |
| - if (variable.MightHaveChildren()) |
160 |
| - body.try_emplace("variablesReference", new_var_ref); |
161 |
| - else |
162 |
| - body.try_emplace("variablesReference", 0); |
163 |
| - if (lldb::addr_t addr = variable.GetLoadAddress(); |
164 |
| - addr != LLDB_INVALID_ADDRESS) |
165 |
| - body.try_emplace("memoryReference", EncodeMemoryReference(addr)); |
166 |
| - if (ValuePointsToCode(variable)) |
167 |
| - body.try_emplace("valueLocationReference", new_var_ref); |
168 |
| - } else { |
169 |
| - EmplaceSafeString(body, "message", std::string(error.GetCString())); |
170 |
| - } |
171 |
| - response["success"] = llvm::json::Value(success); |
| 36 | + constexpr llvm::StringRef return_value_name = "(Return Value)"; |
| 37 | + if (args_name == return_value_name) |
| 38 | + return llvm::make_error<DAPError>( |
| 39 | + "cannot change the value of the return value"); |
| 40 | + |
| 41 | + lldb::SBValue variable = |
| 42 | + dap.variables.FindVariable(args.variablesReference, args_name); |
| 43 | + |
| 44 | + if (!variable.IsValid()) |
| 45 | + return llvm::make_error<DAPError>("could not find variable in scope"); |
| 46 | + |
| 47 | + lldb::SBError error; |
| 48 | + const bool success = variable.SetValueFromCString(args.value.c_str(), error); |
| 49 | + if (!success) |
| 50 | + return llvm::make_error<DAPError>(error.GetCString()); |
| 51 | + |
| 52 | + VariableDescription desc(variable, |
| 53 | + dap.configuration.enableAutoVariableSummaries); |
| 54 | + |
| 55 | + SetVariableResponseBody body; |
| 56 | + body.value = desc.display_value; |
| 57 | + body.type = desc.display_type_name; |
| 58 | + |
| 59 | + // We don't know the index of the variable in our dap.variables |
| 60 | + // so always insert a new one to get its variablesReference. |
| 61 | + // is_permanent is false because debug console does not support |
| 62 | + // setVariable request. |
| 63 | + const int64_t new_var_ref = |
| 64 | + dap.variables.InsertVariable(variable, /*is_permanent=*/false); |
| 65 | + if (variable.MightHaveChildren()) { |
| 66 | + body.variablesReference = new_var_ref; |
| 67 | + if (desc.type_obj.IsArrayType()) |
| 68 | + body.indexedVariables = variable.GetNumChildren(); |
| 69 | + else |
| 70 | + body.namedVariables = variable.GetNumChildren(); |
| 71 | + |
172 | 72 | } else {
|
173 |
| - response["success"] = llvm::json::Value(false); |
| 73 | + body.variablesReference = 0; |
174 | 74 | }
|
175 | 75 |
|
176 |
| - response.try_emplace("body", std::move(body)); |
177 |
| - dap.SendJSON(llvm::json::Value(std::move(response))); |
| 76 | + if (const lldb::addr_t addr = variable.GetLoadAddress(); |
| 77 | + addr != LLDB_INVALID_ADDRESS) |
| 78 | + body.memoryReference = EncodeMemoryReference(addr); |
| 79 | + |
| 80 | + if (ValuePointsToCode(variable)) |
| 81 | + body.valueLocationReference = new_var_ref; |
| 82 | + |
| 83 | + return body; |
178 | 84 | }
|
179 | 85 |
|
180 | 86 | } // namespace lldb_dap
|
0 commit comments