1 //===-- RPCServerSourceEmitter.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 "RPCServerSourceEmitter.h"
10 #include "RPCCommon.h"
11
12 #include "clang/AST/AST.h"
13 #include "clang/Frontend/CompilerInstance.h"
14
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/ToolOutputFile.h"
18 #include "llvm/Support/raw_ostream.h"
19
20 #include <map>
21
22 using namespace clang;
23 using namespace lldb_rpc_gen;
24
25 // For methods with pointer return types, it's important that we know how big
26 // the type of the pointee is. We must correctly size a buffer (in the form of a
27 // Bytes object) before we can actually use it.
28 static const std::map<llvm::StringRef, size_t> MethodsWithPointerReturnTypes = {
29 {"_ZN4lldb12SBModuleSpec12GetUUIDBytesEv", 16}, // sizeof(uuid_t) -> 16
30 {"_ZNK4lldb8SBModule12GetUUIDBytesEv", 16}, // sizeof(uuid_t) -> 16
31 };
32
EmitMethod(const Method & method)33 void RPCServerSourceEmitter::EmitMethod(const Method &method) {
34 if (method.ContainsFunctionPointerParameter)
35 EmitCallbackFunction(method);
36
37 EmitCommentHeader(method);
38 EmitFunctionHeader(method);
39 EmitFunctionBody(method);
40 EmitFunctionFooter();
41 }
42
EmitCommentHeader(const Method & method)43 void RPCServerSourceEmitter::EmitCommentHeader(const Method &method) {
44 std::string CommentLine;
45 llvm::raw_string_ostream CommentStream(CommentLine);
46
47 CommentStream << "// " << method.QualifiedName << "("
48 << method.CreateParamListAsString(eServer) << ")";
49 if (method.IsConst)
50 CommentStream << " const";
51
52 EmitLine("//------------------------------------------------------------");
53 EmitLine(CommentLine);
54 EmitLine("//------------------------------------------------------------");
55 }
56
EmitFunctionHeader(const Method & method)57 void RPCServerSourceEmitter::EmitFunctionHeader(const Method &method) {
58 std::string FunctionHeader;
59 llvm::raw_string_ostream FunctionHeaderStream(FunctionHeader);
60 FunctionHeaderStream
61 << "bool rpc_server::" << method.MangledName
62 << "::HandleRPCCall(rpc_common::Connection &connection, RPCStream "
63 "&send, RPCStream &response) {";
64 EmitLine(FunctionHeader);
65 IndentLevel++;
66 }
67
EmitFunctionBody(const Method & method)68 void RPCServerSourceEmitter::EmitFunctionBody(const Method &method) {
69 EmitLine("// 1) Make local storage for incoming function arguments");
70 EmitStorageForParameters(method);
71 EmitLine("// 2) Decode all function arguments");
72 EmitDecodeForParameters(method);
73 EmitLine("// 3) Call the method and encode the return value");
74 EmitMethodCallAndEncode(method);
75 }
76
EmitFunctionFooter()77 void RPCServerSourceEmitter::EmitFunctionFooter() {
78 EmitLine("return true;");
79 IndentLevel--;
80 EmitLine("}");
81 }
82
EmitStorageForParameters(const Method & method)83 void RPCServerSourceEmitter::EmitStorageForParameters(const Method &method) {
84 // If we have an instance method and it isn't a constructor, we'll need to
85 // emit a "this" pointer.
86 if (method.IsInstance && !method.IsCtor)
87 EmitStorageForOneParameter(method.ThisType, "this_ptr", method.Policy,
88 /* IsFollowedByLen = */ false);
89 for (auto Iter = method.Params.begin(); Iter != method.Params.end(); Iter++) {
90 EmitStorageForOneParameter(Iter->Type, Iter->Name, method.Policy,
91 Iter->IsFollowedByLen);
92 // Skip over the length parameter, we don't emit it.
93 if (!lldb_rpc_gen::TypeIsConstCharPtrPtr(Iter->Type) &&
94 Iter->IsFollowedByLen)
95 Iter++;
96 }
97 }
98
EmitStorageForOneParameter(QualType ParamType,const std::string & ParamName,const PrintingPolicy & Policy,bool IsFollowedByLen)99 void RPCServerSourceEmitter::EmitStorageForOneParameter(
100 QualType ParamType, const std::string &ParamName,
101 const PrintingPolicy &Policy, bool IsFollowedByLen) {
102 // First, we consider `const char *`, `const char **`. They have special
103 // server-side types.
104 if (TypeIsConstCharPtr(ParamType)) {
105 EmitLine("rpc_common::ConstCharPointer " + ParamName + ";");
106 return;
107 } else if (TypeIsConstCharPtrPtr(ParamType)) {
108 EmitLine("rpc_common::StringList " + ParamName + ";");
109 return;
110 }
111
112 QualType UnderlyingType =
113 lldb_rpc_gen::GetUnqualifiedUnderlyingType(ParamType);
114 const bool IsSBClass = lldb_rpc_gen::TypeIsSBClass(UnderlyingType);
115
116 if (ParamType->isPointerType() && !IsSBClass) {
117 // Void pointer with no length is usually a baton for a callback. We're
118 // going to hold onto the pointer value so we can send it back to the
119 // client-side when we implement callbacks.
120 if (ParamType->isVoidPointerType() && !IsFollowedByLen) {
121 EmitLine("void * " + ParamName + " = nullptr;");
122 return;
123 }
124
125 if (!ParamType->isFunctionPointerType()) {
126 EmitLine("Bytes " + ParamName + ";");
127 return;
128 }
129
130 assert(ParamType->isFunctionPointerType() && "Unhandled pointer type");
131 EmitLine("rpc_common::function_ptr_t " + ParamName + " = nullptr;");
132 return;
133 }
134
135 std::string StorageDeclaration;
136 llvm::raw_string_ostream StorageDeclarationStream(StorageDeclaration);
137
138 UnderlyingType.print(StorageDeclarationStream, Policy);
139 StorageDeclarationStream << " ";
140 if (IsSBClass)
141 StorageDeclarationStream << "*";
142 StorageDeclarationStream << ParamName;
143 if (IsSBClass)
144 StorageDeclarationStream << " = nullptr";
145 else
146 StorageDeclarationStream << " = {}";
147 StorageDeclarationStream << ";";
148 EmitLine(StorageDeclaration);
149 }
150
EmitDecodeForParameters(const Method & method)151 void RPCServerSourceEmitter::EmitDecodeForParameters(const Method &method) {
152 if (method.IsInstance && !method.IsCtor)
153 EmitDecodeForOneParameter(method.ThisType, "this_ptr", method.Policy);
154 for (auto Iter = method.Params.begin(); Iter != method.Params.end(); Iter++) {
155 EmitDecodeForOneParameter(Iter->Type, Iter->Name, method.Policy);
156 if (!lldb_rpc_gen::TypeIsConstCharPtrPtr(Iter->Type) &&
157 Iter->IsFollowedByLen)
158 Iter++;
159 }
160 }
161
EmitDecodeForOneParameter(QualType ParamType,const std::string & ParamName,const PrintingPolicy & Policy)162 void RPCServerSourceEmitter::EmitDecodeForOneParameter(
163 QualType ParamType, const std::string &ParamName,
164 const PrintingPolicy &Policy) {
165 QualType UnderlyingType =
166 lldb_rpc_gen::GetUnqualifiedUnderlyingType(ParamType);
167
168 if (TypeIsSBClass(UnderlyingType)) {
169 std::string DecodeLine;
170 llvm::raw_string_ostream DecodeLineStream(DecodeLine);
171 DecodeLineStream << ParamName << " = "
172 << "RPCServerObjectDecoder<";
173 UnderlyingType.print(DecodeLineStream, Policy);
174 DecodeLineStream << ">(send, rpc_common::RPCPacket::ValueType::Argument);";
175 EmitLine(DecodeLine);
176 EmitLine("if (!" + ParamName + ")");
177 IndentLevel++;
178 EmitLine("return false;");
179 IndentLevel--;
180 } else {
181 EmitLine("if (!RPCValueDecoder(send, "
182 "rpc_common::RPCPacket::ValueType::Argument, " +
183 ParamName + "))");
184 IndentLevel++;
185 EmitLine("return false;");
186 IndentLevel--;
187 }
188 }
189
CreateMethodCall(const Method & method)190 std::string RPCServerSourceEmitter::CreateMethodCall(const Method &method) {
191 std::string MethodCall;
192 llvm::raw_string_ostream MethodCallStream(MethodCall);
193 if (method.IsInstance) {
194 if (!method.IsCtor)
195 MethodCallStream << "this_ptr->";
196 MethodCallStream << method.BaseName;
197 } else
198 MethodCallStream << method.QualifiedName;
199
200 std::vector<std::string> Args;
201 std::string FunctionPointerName;
202 for (auto Iter = method.Params.begin(); Iter != method.Params.end(); Iter++) {
203 std::string Arg;
204 // We must check for `const char *` and `const char **` first.
205 if (TypeIsConstCharPtr(Iter->Type)) {
206 // `const char *` is stored server-side as rpc_common::ConstCharPointer
207 Arg = Iter->Name + ".c_str()";
208 } else if (TypeIsConstCharPtrPtr(Iter->Type)) {
209 // `const char **` is stored server-side as rpc_common::StringList
210 Arg = Iter->Name + ".argv()";
211 } else if (lldb_rpc_gen::TypeIsSBClass(Iter->Type)) {
212 Arg = Iter->Name;
213 if (!Iter->Type->isPointerType())
214 Arg = "*" + Iter->Name;
215 } else if (Iter->Type->isPointerType() &&
216 !Iter->Type->isFunctionPointerType() &&
217 (!Iter->Type->isVoidPointerType() || Iter->IsFollowedByLen)) {
218 // We move pointers between the server and client as 'Bytes' objects.
219 // Pointers with length arguments will have their length filled in below.
220 // Pointers with no length arguments are assumed to behave like an array
221 // with length of 1, except for void pointers which are handled
222 // differently.
223 Arg = "(" + Iter->Type.getAsString(method.Policy) + ")" + Iter->Name +
224 ".GetData()";
225 } else if (Iter->Type->isFunctionPointerType()) {
226 // If we have a function pointer, we only want to pass something along if
227 // we got a real pointer.
228 Arg = Iter->Name + " ? " + method.MangledName + "_callback : nullptr";
229 FunctionPointerName = Iter->Name;
230 } else if (Iter->Type->isVoidPointerType() && !Iter->IsFollowedByLen &&
231 method.ContainsFunctionPointerParameter) {
232 // Assumptions:
233 // - This is assumed to be the baton for the function pointer.
234 // - This is assumed to come after the function pointer parameter.
235 // We always produce this regardless of the value of the baton argument.
236 Arg = "new CallbackInfo(" + FunctionPointerName + ", " + Iter->Name +
237 ", connection.GetConnectionID())";
238 } else
239 Arg = Iter->Name;
240
241 if (Iter->Type->isRValueReferenceType())
242 Arg = "std::move(" + Arg + ")";
243 Args.push_back(Arg);
244
245 if (!lldb_rpc_gen::TypeIsConstCharPtrPtr(Iter->Type) &&
246 Iter->IsFollowedByLen) {
247 std::string LengthArg = Iter->Name + ".GetSize()";
248 if (!Iter->Type->isVoidPointerType()) {
249 QualType UUT = lldb_rpc_gen::GetUnqualifiedUnderlyingType(Iter->Type);
250 LengthArg += " / sizeof(" + UUT.getAsString(method.Policy) + ")";
251 }
252 Args.push_back(LengthArg);
253 Iter++;
254 }
255 }
256 MethodCallStream << "(" << llvm::join(Args, ", ") << ")";
257
258 return MethodCall;
259 }
260
CreateEncodeLine(const std::string & Value,bool IsEncodingSBClass)261 std::string RPCServerSourceEmitter::CreateEncodeLine(const std::string &Value,
262 bool IsEncodingSBClass) {
263 std::string EncodeLine;
264 llvm::raw_string_ostream EncodeLineStream(EncodeLine);
265
266 if (IsEncodingSBClass)
267 EncodeLineStream << "RPCServerObjectEncoder(";
268 else
269 EncodeLineStream << "RPCValueEncoder(";
270
271 EncodeLineStream
272 << "response, rpc_common::RPCPacket::ValueType::ReturnValue, ";
273 EncodeLineStream << Value;
274 EncodeLineStream << ");";
275 return EncodeLine;
276 }
277
278 // There are 4 cases to consider:
279 // - const SBClass &: No need to do anything.
280 // - const foo &: No need to do anything.
281 // - SBClass &: The server and the client hold on to IDs to refer to specific
282 // instances, so there's no need to send any information back to the client.
283 // - foo &: The client is sending us a value over the wire, but because the type
284 // is mutable, we must send the changed value back in case the method call
285 // mutated it.
286 //
287 // Updating a mutable reference is done as a return value from the RPC
288 // perspective. These return values need to be emitted after the method's return
289 // value, and they are emitted in the order in which they occur in the
290 // declaration.
EmitEncodesForMutableParameters(const std::vector<Param> & Params)291 void RPCServerSourceEmitter::EmitEncodesForMutableParameters(
292 const std::vector<Param> &Params) {
293 for (auto Iter = Params.begin(); Iter != Params.end(); Iter++) {
294 // No need to manually update an SBClass
295 if (lldb_rpc_gen::TypeIsSBClass(Iter->Type))
296 continue;
297
298 if (!Iter->Type->isReferenceType() && !Iter->Type->isPointerType())
299 continue;
300
301 // If we have a void pointer with no length, there's nothing to update. This
302 // is likely a baton for a callback. The same goes for function pointers.
303 if (Iter->Type->isFunctionPointerType() ||
304 (Iter->Type->isVoidPointerType() && !Iter->IsFollowedByLen))
305 continue;
306
307 // No need to update pointers and references to const-qualified data.
308 QualType UnderlyingType = lldb_rpc_gen::GetUnderlyingType(Iter->Type);
309 if (UnderlyingType.isConstQualified())
310 continue;
311
312 const std::string EncodeLine =
313 CreateEncodeLine(Iter->Name, /* IsEncodingSBClass = */ false);
314 EmitLine(EncodeLine);
315 }
316 }
317
318 // There are 3 possible scenarios that this method can encounter:
319 // 1. The method has no return value and is not a constructor.
320 // Only the method call itself is emitted.
321 // 2. The method is a constructor.
322 // The call to the constructor is emitted in the encode line.
323 // 3. The method has a return value.
324 // The method call is emitted and the return value is captured in a variable.
325 // After that, an encode call is emitted with the variable that captured the
326 // return value.
EmitMethodCallAndEncode(const Method & method)327 void RPCServerSourceEmitter::EmitMethodCallAndEncode(const Method &method) {
328 const std::string MethodCall = CreateMethodCall(method);
329
330 // If this function returns nothing, we just emit the call and update any
331 // mutable references. Note that constructors have return type `void` so we
332 // must explicitly check for that here.
333 if (!method.IsCtor && method.ReturnType->isVoidType()) {
334 EmitLine(MethodCall + ";");
335 EmitEncodesForMutableParameters(method.Params);
336 return;
337 }
338
339 static constexpr llvm::StringLiteral ReturnVariableName("__result");
340
341 // If this isn't a constructor, we'll need to store the result of the method
342 // call in a result variable.
343 if (!method.IsCtor) {
344 // We need to determine what the appropriate return type is. Here is the
345 // strategy:
346 // 1.) `SBFoo` -> `SBFoo &&`
347 // 2.) If the type is a pointer other than `const char *` or `const char **`
348 // or `void *`, the return type will be `Bytes` (e.g. `const uint8_t *`
349 // -> `Bytes`).
350 // 3.) Otherwise, emit the exact same return type.
351 std::string ReturnTypeName;
352 std::string AssignLine;
353 llvm::raw_string_ostream AssignLineStream(AssignLine);
354 if (method.ReturnType->isPointerType() &&
355 !lldb_rpc_gen::TypeIsConstCharPtr(method.ReturnType) &&
356 !lldb_rpc_gen::TypeIsConstCharPtrPtr(method.ReturnType) &&
357 !method.ReturnType->isVoidPointerType()) {
358 llvm::StringRef MangledNameRef(method.MangledName);
359 auto Pos = MethodsWithPointerReturnTypes.find(MangledNameRef);
360 assert(Pos != MethodsWithPointerReturnTypes.end() &&
361 "Unable to determine the size of the return buffer");
362 if (Pos == MethodsWithPointerReturnTypes.end()) {
363 EmitLine(
364 "// Intentionally inserting a compiler error. lldb-rpc-gen "
365 "was unable to determine how large the return buffer should be.");
366 EmitLine("#error: \"unable to determine size of return buffer\"");
367 return;
368 }
369 AssignLineStream << "Bytes " << ReturnVariableName << "(" << MethodCall
370 << ", " << Pos->second << ");";
371 } else {
372 if (lldb_rpc_gen::TypeIsSBClass(method.ReturnType)) {
373 // We want to preserve constness, so we don't strip qualifications from
374 // the underlying type
375 QualType UnderlyingReturnType =
376 lldb_rpc_gen::GetUnderlyingType(method.ReturnType);
377 ReturnTypeName =
378 UnderlyingReturnType.getAsString(method.Policy) + " &&";
379 } else
380 ReturnTypeName = method.ReturnType.getAsString(method.Policy);
381
382 AssignLineStream << ReturnTypeName << " " << ReturnVariableName << " = "
383 << MethodCall << ";";
384 }
385 EmitLine(AssignLine);
386 }
387
388 const bool IsEncodingSBClass =
389 lldb_rpc_gen::TypeIsSBClass(method.ReturnType) || method.IsCtor;
390
391 std::string ValueToEncode;
392 if (IsEncodingSBClass) {
393 if (method.IsCtor)
394 ValueToEncode = MethodCall;
395 else
396 ValueToEncode = "std::move(" + ReturnVariableName.str() + ")";
397 } else
398 ValueToEncode = ReturnVariableName.str();
399
400 const std::string ReturnValueEncodeLine =
401 CreateEncodeLine(ValueToEncode, IsEncodingSBClass);
402 EmitLine(ReturnValueEncodeLine);
403 EmitEncodesForMutableParameters(method.Params);
404 }
405
406 // NOTE: This contains most of the same knowledge as RPCLibrarySourceEmitter. I
407 // have chosen not to re-use code here because the needs are different enough
408 // that it would be more work to re-use than just reimplement portions of it.
409 // Specifically:
410 // - Callbacks do not neatly fit into a `Method` object, which currently
411 // assumes that you have a CXXMethodDecl (We have a FunctionDecl at most).
412 // - We only generate callbacks that have a `void *` baton parameter. We hijack
413 // those baton parameters and treat them differently.
414 // - Callbacks need to do something special for moving SB class references back
415 // to the client-side.
EmitCallbackFunction(const Method & method)416 void RPCServerSourceEmitter::EmitCallbackFunction(const Method &method) {
417 // Check invariants and locate necessary resources
418 Param FuncPointerParam;
419 Param BatonParam;
420 for (const auto &Param : method.Params)
421 if (Param.Type->isFunctionPointerType())
422 FuncPointerParam = Param;
423 else if (Param.Type->isVoidPointerType())
424 BatonParam = Param;
425
426 assert(FuncPointerParam.Type->isFunctionPointerType() &&
427 "Emitting callback function with no function pointer");
428 assert(BatonParam.Type->isVoidPointerType() &&
429 "Emitting callback function with no baton");
430
431 QualType FuncType = FuncPointerParam.Type->getPointeeType();
432 const auto *FuncProtoType = FuncType->getAs<FunctionProtoType>();
433 assert(FuncProtoType && "Emitting callback with no parameter information");
434 if (!FuncProtoType)
435 return; // If asserts are off, we'll just fail to compile.
436
437 std::vector<Param> CallbackParams;
438 std::vector<std::string> CallbackParamsAsStrings;
439 uint8_t ArgIdx = 0;
440 for (QualType ParamType : FuncProtoType->param_types()) {
441 Param CallbackParam;
442 CallbackParam.IsFollowedByLen = false;
443 CallbackParam.Type = ParamType;
444 if (ParamType->isVoidPointerType())
445 CallbackParam.Name = "baton";
446 else
447 CallbackParam.Name = "arg" + std::to_string(ArgIdx++);
448
449 CallbackParams.push_back(CallbackParam);
450 CallbackParamsAsStrings.push_back(ParamType.getAsString(method.Policy) +
451 " " + CallbackParam.Name);
452 }
453 const std::string CallbackReturnTypeName =
454 FuncProtoType->getReturnType().getAsString(method.Policy);
455 const std::string CallbackName = method.MangledName + "_callback";
456
457 // Emit Function Header
458 std::string Header;
459 llvm::raw_string_ostream HeaderStream(Header);
460 HeaderStream << "static " << CallbackReturnTypeName << " " << CallbackName
461 << "(" << llvm::join(CallbackParamsAsStrings, ", ") << ") {";
462 EmitLine(Header);
463 IndentLevel++;
464
465 // Emit Function Body
466 EmitLine("// RPC connection setup and sanity checking");
467 EmitLine("CallbackInfo *callback_info = (CallbackInfo *)baton;");
468 EmitLine("rpc_common::ConnectionSP connection_sp = "
469 "rpc_common::Connection::GetConnectionFromID(callback_info->"
470 "connection_id);");
471 EmitLine("if (!connection_sp)");
472 IndentLevel++;
473 if (FuncProtoType->getReturnType()->isVoidType())
474 EmitLine("return;");
475 else
476 EmitLine("return {};");
477 IndentLevel--;
478
479 EmitLine("// Preparing to make the call");
480 EmitLine("static RPCFunctionInfo g_func(\"" + CallbackName + "\");");
481 EmitLine("RPCStream send;");
482 EmitLine("RPCStream response;");
483 EmitLine("g_func.Encode(send);");
484
485 EmitLine("// The first thing we encode is the callback address so that the "
486 "client-side can know where the callback is");
487 EmitLine("RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, "
488 "callback_info->callback);");
489 EmitLine("// Encode all the arguments");
490 for (const Param &CallbackParam : CallbackParams) {
491 if (lldb_rpc_gen::TypeIsSBClass(CallbackParam.Type)) {
492
493 // FIXME: SB class server references are stored as non-const references so
494 // that we can actually change them as needed. If a parameter is marked
495 // const, we will fail to compile because we cannot make an
496 // SBFooServerReference from a `const SBFoo &`.
497 // To work around this issue, we'll apply a `const_cast` if needed so we
498 // can continue to generate callbacks for now, but we really should
499 // rethink the way we store object IDs server-side to support
500 // const-qualified parameters.
501 QualType UnderlyingSBClass =
502 lldb_rpc_gen::GetUnderlyingType(CallbackParam.Type);
503 QualType UnqualifiedUnderlyingSBClass =
504 UnderlyingSBClass.getUnqualifiedType();
505
506 std::string SBClassName = GetSBClassNameFromType(UnderlyingSBClass);
507 llvm::StringRef SBClassNameRef(SBClassName);
508 SBClassNameRef.consume_front("lldb::");
509
510 std::string ServerReferenceLine;
511 llvm::raw_string_ostream ServerReferenceLineStream(ServerReferenceLine);
512 ServerReferenceLineStream << "rpc_server::" << SBClassNameRef
513 << "ServerReference " << CallbackParam.Name
514 << "_ref(";
515
516 if (UnderlyingSBClass.isConstQualified()) {
517 QualType NonConstSBType =
518 method.Context.getLValueReferenceType(UnqualifiedUnderlyingSBClass);
519 ServerReferenceLineStream << "const_cast<" << NonConstSBType << ">(";
520 }
521 ServerReferenceLineStream << CallbackParam.Name;
522 if (UnderlyingSBClass.isConstQualified())
523 ServerReferenceLineStream << ")";
524
525 ServerReferenceLineStream << ");";
526 EmitLine(ServerReferenceLine);
527 EmitLine(
528 CallbackParam.Name +
529 "_ref.Encode(send, rpc_common::RPCPacket::ValueType::Argument);");
530 } else {
531 std::string ParamName;
532 if (CallbackParam.Type->isVoidPointerType())
533 ParamName = "callback_info->baton";
534 else
535 ParamName = CallbackParam.Name;
536 EmitLine(
537 "RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, " +
538 ParamName + ");");
539 }
540 }
541
542 if (!FuncProtoType->getReturnType()->isVoidType()) {
543 EmitLine("// Storage for return value");
544 const bool ReturnsSBClass =
545 lldb_rpc_gen::TypeIsSBClass(FuncProtoType->getReturnType());
546 std::string ReturnValueLine = CallbackReturnTypeName;
547 llvm::raw_string_ostream ReturnValueLineStream(ReturnValueLine);
548
549 if (ReturnsSBClass)
550 ReturnValueLineStream << " *";
551 ReturnValueLineStream << " __result = ";
552 if (ReturnsSBClass)
553 ReturnValueLineStream << "nullptr";
554 else
555 ReturnValueLineStream << "{}";
556 ReturnValueLineStream << ";";
557 EmitLine(ReturnValueLine);
558 }
559
560 EmitLine(
561 "if (connection_sp->SendRPCCallAndWaitForResponse(send, response)) {");
562 IndentLevel++;
563 if (!FuncProtoType->getReturnType()->isVoidType()) {
564 if (lldb_rpc_gen::TypeIsSBClass(FuncProtoType->getReturnType())) {
565 EmitLine("__result = rpc_server::RPCServerObjectDecoder<" +
566 CallbackReturnTypeName +
567 ">(response, rpc_common::RPCPacket::ValueType::ReturnValue);");
568 } else
569 EmitLine("RPCValueDecoder(response, "
570 "rpc_common::RPCPacket::ValueType::ReturnValue, __result);");
571 }
572 IndentLevel--;
573 EmitLine("}");
574 if (!FuncProtoType->getReturnType()->isVoidType()) {
575 if (lldb_rpc_gen::TypeIsSBClass(FuncProtoType->getReturnType()))
576 EmitLine("return *__result;");
577 else
578 EmitLine("return __result;");
579 }
580
581 // Emit Function Footer;
582 IndentLevel--;
583 EmitLine("};");
584 }
585