|
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