in tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp [478:1040]
void handleRequestImpl(sourcekitd_object_t ReqObj,
SourceKitCancellationToken CancellationToken,
ResponseReceiver Rec) {
// NOTE: if we had a connection context, these stats should move into it.
static Statistic numRequests(UIdentFromSKDUID(KindStatNumRequests), "# of requests (total)");
static Statistic numSemaRequests(UIdentFromSKDUID(KindStatNumSemaRequests), "# of semantic requests");
++numRequests;
RequestDict Req(ReqObj);
if (auto SimulateLongRequestDuration =
Req.getOptionalInt64(KeySimulateLongRequest)) {
if (!getGlobalContext().getSlowRequestSimulator()->simulateLongRequest(
*SimulateLongRequestDuration, CancellationToken)) {
Rec(createErrorRequestCancelled());
return;
}
}
sourcekitd_uid_t ReqUID = Req.getUID(KeyRequest);
if (!ReqUID)
return Rec(createErrorRequestInvalid("missing 'key.request' with UID value"));
if (ReqUID == RequestGlobalConfiguration) {
auto Config = getGlobalContext().getGlobalConfiguration();
ResponseBuilder RB;
auto dict = RB.getDictionary();
Optional<unsigned> CompletionMaxASTContextReuseCount =
Req.getOptionalInt64(KeyCompletionMaxASTContextReuseCount)
.map([](int64_t v) -> unsigned { return v; });
Optional<unsigned> CompletionCheckDependencyInterval =
Req.getOptionalInt64(KeyCompletionCheckDependencyInterval)
.map([](int64_t v) -> unsigned { return v; });
GlobalConfig::Settings UpdatedConfig =
Config->update(CompletionMaxASTContextReuseCount,
CompletionCheckDependencyInterval);
getGlobalContext().getSwiftLangSupport().globalConfigurationUpdated(Config);
dict.set(KeyCompletionMaxASTContextReuseCount,
UpdatedConfig.CompletionOpts.MaxASTContextReuseCount);
dict.set(KeyCompletionCheckDependencyInterval,
UpdatedConfig.CompletionOpts.CheckDependencyInterval);
return Rec(RB.createResponse());
}
if (ReqUID == RequestProtocolVersion) {
ResponseBuilder RB;
auto dict = RB.getDictionary();
dict.set(KeyVersionMajor, ProtocolMajorVersion);
dict.set(KeyVersionMinor, static_cast<int64_t>(ProtocolMinorVersion));
return Rec(RB.createResponse());
}
if (ReqUID == RequestCompilerVersion) {
ResponseBuilder RB;
auto dict = RB.getDictionary();
auto thisVersion = swift::version::Version::getCurrentLanguageVersion();
dict.set(KeyVersionMajor, static_cast<int64_t>(thisVersion[0]));
dict.set(KeyVersionMinor, static_cast<int64_t>(thisVersion[1]));
if (thisVersion.size() > 2)
dict.set(KeyVersionPatch, static_cast<int64_t>(thisVersion[2]));
else
dict.set(KeyVersionPatch, static_cast<int64_t>(0));
return Rec(RB.createResponse());
}
if (ReqUID == RequestCrashWithExit) {
// 'exit' has the same effect as crashing but without the crash log.
::exit(1);
}
if (ReqUID == RequestTestNotification) {
getGlobalContext().getNotificationCenter()->postTestNotification();
return Rec(ResponseBuilder().createResponse());
}
if (ReqUID == RequestDemangle) {
SmallVector<const char *, 8> MangledNames;
bool Failed = Req.getStringArray(KeyNames, MangledNames, /*isOptional=*/true);
if (Failed) {
return Rec(createErrorRequestInvalid(
"'key.names' not an array of strings"));
}
int64_t Simplified = false;
Req.getInt64(KeySimplified, Simplified, /*isOptional=*/true);
return Rec(demangleNames(MangledNames, Simplified));
}
if (ReqUID == RequestMangleSimpleClass) {
SmallVector<std::pair<StringRef, StringRef>, 16> ModuleClassPairs;
sourcekitd_response_t err = nullptr;
bool failed = Req.dictionaryArrayApply(KeyNames, [&](RequestDict dict) {
Optional<StringRef> ModuleName = dict.getString(KeyModuleName);
if (!ModuleName.hasValue()) {
err = createErrorRequestInvalid("missing 'key.modulename'");
return true;
}
Optional<StringRef> ClassName = dict.getString(KeyName);
if (!ClassName.hasValue()) {
err = createErrorRequestInvalid("missing 'key.name'");
return true;
}
ModuleClassPairs.push_back(std::make_pair(*ModuleName, *ClassName));
return false;
});
if (failed) {
if (!err)
err = createErrorRequestInvalid("missing 'key.names'");
return Rec(err);
}
return Rec(mangleSimpleClassNames(ModuleClassPairs));
}
if (ReqUID == RequestEnableCompileNotifications) {
int64_t value = true;
if (Req.getInt64(KeyValue, value, /*isOptional=*/false)) {
return Rec(createErrorRequestInvalid("missing 'key.value'"));
}
enableCompileNotifications(value);
return Rec(ResponseBuilder().createResponse());
}
// Just accept 'source.request.buildsettings.register' for now, don't do
// anything else.
// FIXME: Heavy WIP here.
if (ReqUID == RequestBuildSettingsRegister) {
return Rec(ResponseBuilder().createResponse());
}
if (ReqUID == RequestDependencyUpdated) {
getGlobalContext().getSwiftLangSupport().dependencyUpdated();
return Rec(ResponseBuilder().createResponse());
}
Optional<StringRef> SourceFile = Req.getString(KeySourceFile);
Optional<StringRef> SourceText = Req.getString(KeySourceText);
llvm::SmallString<64> ErrBuf;
Optional<VFSOptions> vfsOptions;
if (Optional<StringRef> VFSName = Req.getString(KeyVFSName)) {
if (ReqUID != RequestEditorOpen && ReqUID != RequestCodeComplete &&
ReqUID != RequestCodeCompleteOpen && ReqUID != RequestCursorInfo) {
return Rec(createErrorRequestInvalid(
"This request does not support custom filesystems"));
}
vfsOptions = getVFSOptions(Req);
}
SmallVector<const char *, 8> Args;
bool Failed = Req.getStringArray(KeyCompilerArgs, Args, /*isOptional=*/true);
if (Failed) {
return Rec(createErrorRequestInvalid(
"'key.compilerargs' not an array of strings"));
}
if (ReqUID == RequestDocInfo) {
std::unique_ptr<llvm::MemoryBuffer> InputBuf = getInputBufForRequest(
SourceFile, SourceText, vfsOptions, ErrBuf);
if (!InputBuf)
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
StringRef ModuleName;
Optional<StringRef> ModuleNameOpt = Req.getString(KeyModuleName);
if (ModuleNameOpt.hasValue()) ModuleName = *ModuleNameOpt;
return Rec(reportDocInfo(InputBuf.get(), ModuleName, Args));
}
if (ReqUID == RequestEditorOpen) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
std::unique_ptr<llvm::MemoryBuffer> InputBuf =
getInputBufForRequest(SourceFile, SourceText, vfsOptions, ErrBuf);
if (!InputBuf)
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
int64_t EnableSyntaxMap = true;
Req.getInt64(KeyEnableSyntaxMap, EnableSyntaxMap, /*isOptional=*/true);
int64_t EnableStructure = true;
Req.getInt64(KeyEnableStructure, EnableStructure, /*isOptional=*/true);
int64_t EnableDiagnostics = true;
Req.getInt64(KeyEnableDiagnostics, EnableDiagnostics, /*isOptional=*/true);
auto TransferModeUID = Req.getUID(KeySyntaxTreeTransferMode);
int64_t SyntacticOnly = false;
Req.getInt64(KeySyntacticOnly, SyntacticOnly, /*isOptional=*/true);
SKEditorConsumerOptions Opts;
Opts.EnableSyntaxMap = EnableSyntaxMap;
Opts.EnableStructure = EnableStructure;
Opts.EnableDiagnostics = EnableDiagnostics;
Opts.SyntaxTransferMode = syntaxTransferModeFromUID(TransferModeUID);
Opts.SyntacticOnly = SyntacticOnly;
return Rec(editorOpen(*Name, InputBuf.get(), Opts, Args, std::move(vfsOptions)));
}
if (ReqUID == RequestEditorClose) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
// Whether we remove the cached AST from libcache, by default, false.
int64_t RemoveCache = false;
Req.getInt64(KeyRemoveCache, RemoveCache, /*isOptional=*/true);
return Rec(editorClose(*Name, RemoveCache));
}
if (ReqUID == RequestEditorReplaceText) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
std::unique_ptr<llvm::MemoryBuffer> InputBuf = getInputBufForRequest(
SourceFile, SourceText, vfsOptions, ErrBuf);
if (!InputBuf)
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
int64_t Offset = 0;
Req.getInt64(KeyOffset, Offset, /*isOptional=*/true);
int64_t Length = 0;
Req.getInt64(KeyLength, Length, /*isOptional=*/true);
int64_t EnableSyntaxMap = true;
Req.getInt64(KeyEnableSyntaxMap, EnableSyntaxMap, /*isOptional=*/true);
int64_t EnableStructure = true;
Req.getInt64(KeyEnableStructure, EnableStructure, /*isOptional=*/true);
int64_t EnableDiagnostics = true;
Req.getInt64(KeyEnableDiagnostics, EnableDiagnostics, /*isOptional=*/true);
int64_t SyntacticOnly = false;
Req.getInt64(KeySyntacticOnly, SyntacticOnly, /*isOptional=*/true);
auto TransferModeUID = Req.getUID(KeySyntaxTreeTransferMode);
SKEditorConsumerOptions Opts;
Opts.EnableSyntaxMap = EnableSyntaxMap;
Opts.EnableStructure = EnableStructure;
Opts.EnableDiagnostics = EnableDiagnostics;
Opts.SyntaxTransferMode = syntaxTransferModeFromUID(TransferModeUID);
Opts.SyntacticOnly = SyntacticOnly;
return Rec(editorReplaceText(*Name, InputBuf.get(), Offset, Length, Opts));
}
if (ReqUID == RequestEditorFormatText) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
Optional<RequestDict> FmtOptions = Req.getDictionary(KeyFormatOptions);
if (FmtOptions.hasValue())
editorApplyFormatOptions(*Name, *FmtOptions);
int64_t Line = 0;
Req.getInt64(KeyLine, Line, /*isOptional=*/false);
int64_t Length = 0;
Req.getInt64(KeyLength, Length, /*isOptional=*/true);
return Rec(editorFormatText(*Name, Line, Length));
}
if (ReqUID == RequestEditorExpandPlaceholder) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
int64_t Offset = 0;
Req.getInt64(KeyOffset, Offset, /*isOptional=*/false);
int64_t Length = 0;
Req.getInt64(KeyLength, Length, /*isOptional=*/false);
return Rec(editorExpandPlaceholder(*Name, Offset, Length));
}
if (ReqUID == RequestEditorOpenInterface) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
Optional<StringRef> ModuleName = Req.getString(KeyModuleName);
if (!ModuleName.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.modulename'"));
Optional<StringRef> GroupName = Req.getString(KeyGroupName);
int64_t SynthesizedExtension = false;
Req.getInt64(KeySynthesizedExtension, SynthesizedExtension,
/*isOptional=*/true);
Optional<StringRef> InterestedUSR = Req.getString(KeyInterestedUSR);
return Rec(editorOpenInterface(*Name, *ModuleName, GroupName, Args,
SynthesizedExtension, InterestedUSR));
}
if (ReqUID == RequestEditorOpenHeaderInterface) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
Optional<StringRef> HeaderName = Req.getString(KeyFilePath);
if (!HeaderName.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.filepath'"));
int64_t SynthesizedExtension = false;
Req.getInt64(KeySynthesizedExtension, SynthesizedExtension,
/*isOptional=*/true);
Optional<int64_t> UsingSwiftArgs = Req.getOptionalInt64(KeyUsingSwiftArgs);
std::string swiftVer;
Optional<StringRef> swiftVerValStr = Req.getString(KeySwiftVersion);
if (swiftVerValStr.hasValue()) {
swiftVer = swiftVerValStr.getValue().str();
} else {
Optional<int64_t> swiftVerVal = Req.getOptionalInt64(KeySwiftVersion);
if (swiftVerVal.hasValue())
swiftVer = std::to_string(*swiftVerVal);
}
return Rec(editorOpenHeaderInterface(*Name, *HeaderName, Args,
UsingSwiftArgs.getValueOr(false),
SynthesizedExtension, swiftVer));
}
if (ReqUID == RequestEditorOpenSwiftSourceInterface) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
Optional<StringRef> FileName = Req.getString(KeySourceFile);
if (!FileName.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.sourcefile'"));
return editorOpenSwiftSourceInterface(*Name, *FileName, Args,
CancellationToken, Rec);
}
if (ReqUID == RequestEditorOpenSwiftTypeInterface) {
Optional<StringRef> Usr = Req.getString(KeyUSR);
if (!Usr.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.usr'"));
return editorOpenSwiftTypeInterface(*Usr, Args, Rec);
}
if (ReqUID == RequestEditorExtractTextFromComment) {
Optional<StringRef> Source = Req.getString(KeySourceText);
if (!Source.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.sourcetext'"));
return Rec(editorExtractTextFromComment(Source.getValue()));
}
if (ReqUID == RequestMarkupToXML) {
Optional<StringRef> Source = Req.getString(KeySourceText);
if (!Source.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.sourcetext'"));
return Rec(editorConvertMarkupToXML(Source.getValue()));
}
if (ReqUID == RequestEditorFindUSR) {
Optional<StringRef> Name = Req.getString(KeySourceFile);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.sourcefile'"));
Optional<StringRef> USR = Req.getString(KeyUSR);
if (!USR.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.usr'"));
return Rec(editorFindUSR(*Name, *USR));
}
if (ReqUID == RequestEditorFindInterfaceDoc) {
Optional<StringRef> ModuleName = Req.getString(KeyModuleName);
if (!ModuleName.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.modulename'"));
return Rec(editorFindInterfaceDoc(*ModuleName, Args));
}
if (ReqUID == RequestModuleGroups) {
Optional<StringRef> ModuleName = Req.getString(KeyModuleName);
if (!ModuleName.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.modulename'"));
return Rec(editorFindModuleGroups(*ModuleName, Args));
}
if (ReqUID == RequestSyntacticRename) {
std::unique_ptr<llvm::MemoryBuffer> InputBuf = getInputBufForRequest(
SourceFile, SourceText, vfsOptions, ErrBuf);
if (!InputBuf)
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
std::vector<RenameLocations> RenameLocations;
if (buildRenameLocationsFromDict(Req, true, RenameLocations, ErrBuf))
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
return Rec(syntacticRename(InputBuf.get(), RenameLocations, Args));
}
if (ReqUID == RequestFindRenameRanges) {
std::unique_ptr<llvm::MemoryBuffer> InputBuf = getInputBufForRequest(
SourceFile, SourceText, vfsOptions, ErrBuf);
if (!InputBuf)
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
std::vector<RenameLocations> RenameLocations;
if (buildRenameLocationsFromDict(Req, false, RenameLocations, ErrBuf))
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
return Rec(findRenameRanges(InputBuf.get(), RenameLocations, Args));
}
if (ReqUID == RequestCodeCompleteClose) {
// Unlike opening code completion, this is not a semantic request.
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
int64_t Offset;
if (Req.getInt64(KeyOffset, Offset, /*isOptional=*/false))
return Rec(createErrorRequestInvalid("missing 'key.offset'"));
return Rec(codeCompleteClose(*Name, Offset));
}
if (ReqUID == RequestCodeCompleteCacheOnDisk) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.codeCompleteCacheOnDisk(*Name);
ResponseBuilder b;
return Rec(b.createResponse());
}
if (ReqUID == RequestCodeCompleteSetPopularAPI) {
llvm::SmallVector<const char *, 0> popular;
llvm::SmallVector<const char *, 0> unpopular;
Req.getStringArray(KeyPopular, popular, /*isOptional=*/false);
Req.getStringArray(KeyUnpopular, unpopular, /*isOptional=*/false);
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.codeCompleteSetPopularAPI(popular, unpopular);
ResponseBuilder b;
return Rec(b.createResponse());
}
if (ReqUID == RequestCodeCompleteSetCustom) {
SmallVector<CustomCompletionInfo, 16> customCompletions;
sourcekitd_response_t err = nullptr;
bool failed = Req.dictionaryArrayApply(KeyResults, [&](RequestDict dict) {
CustomCompletionInfo CCInfo;
Optional<StringRef> Name = dict.getString(KeyName);
if (!Name.hasValue()) {
err = createErrorRequestInvalid("missing 'key.name'");
return true;
}
CCInfo.Name = (*Name).str();
sourcekitd_uid_t Kind = dict.getUID(KeyKind);
if (!Kind) {
err = createErrorRequestInvalid("missing 'key.kind'");
return true;
}
CCInfo.Kind = Kind;
SmallVector<sourcekitd_uid_t, 3> contexts;
if (dict.getUIDArray(KeyContext, contexts, false)) {
err = createErrorRequestInvalid("missing 'key.context'");
return true;
}
for (auto context : contexts) {
if (context == KindExpr) {
CCInfo.Contexts |= CustomCompletionInfo::Expr;
} else if (context == KindStmt) {
CCInfo.Contexts |= CustomCompletionInfo::Stmt;
} else if (context == KindType) {
CCInfo.Contexts |= CustomCompletionInfo::Type;
} else if (context == KindForEachSequence) {
CCInfo.Contexts |= CustomCompletionInfo::ForEachSequence;
} else {
err = createErrorRequestInvalid("invalid value for 'key.context'");
return true;
}
}
customCompletions.push_back(std::move(CCInfo));
return false;
});
if (failed) {
if (!err)
err = createErrorRequestInvalid("missing 'key.results'");
return Rec(err);
}
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.codeCompleteSetCustom(customCompletions);
return Rec(ResponseBuilder().createResponse());
}
if (ReqUID == RequestStatistics) {
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.getStatistics([Rec](ArrayRef<Statistic *> stats) {
ResponseBuilder builder;
auto results = builder.getDictionary().setArray(KeyResults);
auto addStat = [&results](Statistic *stat) {
auto dict = results.appendDictionary();
dict.set(KeyKind, stat->name);
dict.set(KeyDescription, stat->description);
dict.set(KeyValue, stat->value);
};
Statistic instructionCount(
UIdentFromSKDUID(KindStatInstructionCount),
"# of instructions executed since the SourceKit process was started");
instructionCount.value.store(swift::getInstructionsExecuted());
addStat(&instructionCount);
addStat(&numRequests);
addStat(&numSemaRequests);
std::for_each(stats.begin(), stats.end(), addStat);
Rec(builder.createResponse());
});
return;
}
if (ReqUID == RequestCompile) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.performCompile(
*Name, Args, std::move(vfsOptions), CancellationToken,
[Rec](const RequestResult<CompilationResult> &result) {
if (result.isCancelled())
return Rec(createErrorRequestCancelled());
if (result.isError())
return Rec(createErrorRequestFailed(result.getError()));
const CompilationResult &info = result.value();
ResponseBuilder builder;
builder.getDictionary().set(KeyValue, info.ResultStatus);
auto diagsArray = builder.getDictionary().setArray(KeyDiagnostics);
for (auto diagInfo : info.Diagnostics) {
auto elem = diagsArray.appendDictionary();
fillDictionaryForDiagnosticInfo(elem, diagInfo);
}
Rec(builder.createResponse());
});
return;
}
if (ReqUID == RequestCompileClose) {
Optional<StringRef> Name = Req.getString(KeyName);
if (!Name.hasValue())
return Rec(createErrorRequestInvalid("missing 'key.name'"));
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.closeCompile(*Name);
return Rec(ResponseBuilder().createResponse());
}
if (!SourceFile.hasValue() && !SourceText.hasValue() &&
ReqUID != RequestCodeCompleteUpdate)
return Rec(createErrorRequestInvalid(
"missing 'key.sourcefile' or 'key.sourcetext'"));
// Requests that need semantic typechecking.
// Typechecking arrays can blow up the stack currently.
// Run them under a malloc'ed stack.
static WorkQueue SemaQueue{ WorkQueue::Dequeuing::Concurrent,
"sourcekit.request.semantic" };
sourcekitd_request_retain(ReqObj);
++numSemaRequests;
SemaQueue.dispatch(
[ReqObj, Rec, ReqUID, SourceFile, SourceText, Args, CancellationToken] {
RequestDict Req(ReqObj);
auto vfsOptions = getVFSOptions(Req);
handleSemanticRequest(Req, Rec, ReqUID, SourceFile, SourceText, Args,
std::move(vfsOptions), CancellationToken);
sourcekitd_request_release(ReqObj);
},
/*isStackDeep=*/true);
}