Skip to content

Commit 8e0ff51

Browse files
committed
[sourcekitd-test] Add -async flag to request options
This enables testing asyncronous requests on platforms that support it (currently you need blocks support to call sourcekitd_send_request). The implementation performs all -async requests and then at the end handles all the responses in the order they were performed (possibly blocking until they complete). Also add a -dont-print-request flag to avoid printing request objects; printing is fairly slow and makes it much harder to hit timing-sensitive races, etc.
1 parent fe2c2d1 commit 8e0ff51

File tree

4 files changed

+100
-9
lines changed

4 files changed

+100
-9
lines changed

tools/SourceKit/tools/sourcekitd-test/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ def check_interface_is_ascii : Flag<["-"], "check-interface-ascii">,
6464
def json_request_path: Separate<["-"], "json-request-path">,
6565
HelpText<"path to read a request in JSON format">;
6666

67+
def dont_print_request : Flag<["-"], "dont-print-request">,
68+
HelpText<"Don't print the request">;
69+
6770
def print_response_as_json : Flag<["-"], "print-response-as-json">,
6871
HelpText<"Print the response as JSON output">;
6972

@@ -81,3 +84,6 @@ def synthesized_extension : Flag<["-"], "synthesized-extension">,
8184

8285
def interested_usr : Separate<["-"], "interested-usr">,
8386
HelpText<"Interested USR to calculate the containing group">;
87+
88+
def async : Flag<["-"], "async">,
89+
HelpText<"Perform request asynchronously">;

tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
216216
CheckInterfaceIsASCII = true;
217217
break;
218218

219+
case OPT_dont_print_request:
220+
PrintRequest = false;
221+
break;
222+
219223
case OPT_print_response_as_json:
220224
PrintResponseAsJSON = true;
221225
break;
@@ -242,12 +246,22 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
242246
SynthesizedExtensions = true;
243247
break;
244248

249+
case OPT_async:
250+
isAsyncRequest = true;
251+
break;
252+
245253
case OPT_UNKNOWN:
246254
llvm::errs() << "error: unknown argument: "
247255
<< InputArg->getAsString(ParsedArgs) << '\n';
248256
return true;
249257
}
250258
}
251259

260+
if (Request == SourceKitRequest::InterfaceGenOpen && isAsyncRequest) {
261+
llvm::errs()
262+
<< "error: cannot use -async with interface-gen-open request\n";
263+
return true;
264+
}
265+
252266
return false;
253267
}

tools/SourceKit/tools/sourcekitd-test/TestOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,12 @@ struct TestOptions {
7474
std::string USR;
7575
bool CheckInterfaceIsASCII = false;
7676
bool UsedSema = false;
77+
bool PrintRequest = true;
7778
bool PrintResponseAsJSON = false;
7879
bool PrintRawResponse = false;
7980
bool SimplifiedDemangling = false;
8081
bool SynthesizedExtensions = false;
82+
bool isAsyncRequest = false;
8183
bool parseArgs(llvm::ArrayRef<const char *> Args);
8284
};
8385

tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ using namespace llvm;
3636
using namespace sourcekitd_test;
3737

3838
static int handleTestInvocation(ArrayRef<const char *> Args, TestOptions &InitOpts);
39+
static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts,
40+
const std::string &SourceFile,
41+
std::unique_ptr<llvm::MemoryBuffer> SourceBuf,
42+
TestOptions *InitOpts);
3943
static void printCursorInfo(sourcekitd_variant_t Info, StringRef Filename,
4044
llvm::raw_ostream &OS);
4145
static void printDocInfo(sourcekitd_variant_t Info, StringRef Filename);
@@ -156,6 +160,18 @@ static SourceKit::Semaphore semaSemaphore(0);
156160
static sourcekitd_response_t semaResponse;
157161
static const char *semaName;
158162

163+
namespace {
164+
struct AsyncResponseInfo {
165+
SourceKit::Semaphore semaphore{0};
166+
sourcekitd_response_t response = nullptr;
167+
TestOptions options;
168+
std::string sourceFilename;
169+
std::unique_ptr<llvm::MemoryBuffer> sourceBuffer;
170+
};
171+
}
172+
173+
static std::vector<AsyncResponseInfo> asyncResponses;
174+
159175
static int skt_main(int argc, const char **argv);
160176

161177
int main(int argc, const char **argv) {
@@ -265,17 +281,32 @@ static int skt_main(int argc, const char **argv) {
265281
}
266282
if (i == Args.size())
267283
break;
268-
int ret = handleTestInvocation(Args.slice(0, i), InitOpts);
269-
if (ret) {
284+
if (int ret = handleTestInvocation(Args.slice(0, i), InitOpts)) {
270285
sourcekitd_shutdown();
271286
return ret;
272287
}
273288
Args = Args.slice(i+1);
274289
}
275290

276-
int ret = handleTestInvocation(Args, InitOpts);
291+
if (int ret = handleTestInvocation(Args, InitOpts)) {
292+
sourcekitd_shutdown();
293+
return ret;
294+
}
295+
296+
for (auto &info : asyncResponses) {
297+
if (info.semaphore.wait(60 * 1000)) {
298+
llvm::report_fatal_error("async request timed out");
299+
}
300+
301+
if (handleResponse(info.response, info.options, info.sourceFilename,
302+
std::move(info.sourceBuffer), nullptr)) {
303+
sourcekitd_shutdown();
304+
return 1;
305+
}
306+
}
307+
277308
sourcekitd_shutdown();
278-
return ret;
309+
return 0;
279310
}
280311

281312
static inline const char *getInterfaceGenDocumentName() {
@@ -665,8 +696,45 @@ static int handleTestInvocation(ArrayRef<const char *> Args,
665696
Opts.HeaderPath.c_str());
666697
}
667698

668-
sourcekitd_request_description_dump(Req);
669-
sourcekitd_response_t Resp = sourcekitd_send_request_sync(Req);
699+
if (Opts.PrintRequest)
700+
sourcekitd_request_description_dump(Req);
701+
702+
if (!Opts.isAsyncRequest) {
703+
sourcekitd_response_t Resp = sourcekitd_send_request_sync(Req);
704+
sourcekitd_request_release(Req);
705+
return handleResponse(Resp, Opts, SourceFile, std::move(SourceBuf),
706+
&InitOpts)
707+
? 1
708+
: 0;
709+
} else {
710+
#if SOURCEKITD_HAS_BLOCKS
711+
AsyncResponseInfo info;
712+
info.options = Opts;
713+
info.sourceFilename = std::move(SourceFile);
714+
info.sourceBuffer = std::move(SourceBuf);
715+
unsigned respIndex = asyncResponses.size();
716+
asyncResponses.push_back(std::move(info));
717+
718+
sourcekitd_send_request(Req, nullptr, ^(sourcekitd_response_t resp) {
719+
auto &info = asyncResponses[respIndex];
720+
info.response = resp;
721+
info.semaphore.signal(); // Ready to be handled!
722+
});
723+
724+
#else
725+
llvm::report_fatal_error(
726+
"-async not supported when sourcekitd is built without blocks support");
727+
#endif
728+
729+
sourcekitd_request_release(Req);
730+
return 0;
731+
}
732+
}
733+
734+
static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts,
735+
const std::string &SourceFile,
736+
std::unique_ptr<llvm::MemoryBuffer> SourceBuf,
737+
TestOptions *InitOpts) {
670738
bool KeepResponseAlive = false;
671739
bool IsError = sourcekitd_response_is_error(Resp);
672740
if (IsError) {
@@ -742,8 +810,10 @@ static int handleTestInvocation(ArrayRef<const char *> Args,
742810

743811
case SourceKitRequest::InterfaceGenOpen:
744812
// Just initialize the options for the subsequent request.
745-
InitOpts.SourceFile = getInterfaceGenDocumentName();
746-
InitOpts.SourceText =
813+
assert(!Opts.isAsyncRequest && InitOpts &&
814+
"async interface-gen-open is not supported");
815+
InitOpts->SourceFile = getInterfaceGenDocumentName();
816+
InitOpts->SourceText =
747817
sourcekitd_variant_dictionary_get_string(Info, KeySourceText);
748818
break;
749819

@@ -832,7 +902,6 @@ static int handleTestInvocation(ArrayRef<const char *> Args,
832902

833903
if (!KeepResponseAlive)
834904
sourcekitd_response_dispose(Resp);
835-
sourcekitd_request_release(Req);
836905
return IsError;
837906
}
838907

0 commit comments

Comments
 (0)