void handleRequestImpl()

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);
}