static int handleTestInvocation()

in tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp [559:1260]


static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) {
  if (!Opts.JsonRequestPath.empty())
    return handleJsonRequestPath(Opts.JsonRequestPath, Opts);

  if (Opts.Request == SourceKitRequest::DemangleNames ||
      Opts.Request == SourceKitRequest::MangleSimpleClasses)
    Opts.SourceFile.clear();

  std::string SourceFile = Opts.SourceFile;
  if (!SourceFile.empty()) {
    llvm::SmallString<64> AbsSourceFile;
    AbsSourceFile += SourceFile;
    llvm::sys::fs::make_absolute(AbsSourceFile);
    llvm::sys::path::native(AbsSourceFile);
    SourceFile = std::string(AbsSourceFile.str());
  }
  std::string SemaName = !Opts.Name.empty() ? Opts.Name : SourceFile;

  if (!Opts.TextInputFile.empty()) {
    auto Buf = getBufferForFilename(Opts.TextInputFile, Opts.VFSFiles);
    Opts.SourceText = Buf->getBuffer().str();
  }

  std::unique_ptr<llvm::MemoryBuffer> SourceBuf;
  if (Opts.SourceText.hasValue()) {
    SourceBuf = llvm::MemoryBuffer::getMemBuffer(*Opts.SourceText, Opts.SourceFile);
  } else if (!SourceFile.empty()) {
    SourceBuf = llvm::MemoryBuffer::getMemBuffer(
        getBufferForFilename(SourceFile, Opts.VFSFiles)->getBuffer(),
        SourceFile);
  }

  // FIXME: we should detect if offset is required but not set.
  unsigned ByteOffset = Opts.Offset;
  if (Opts.Line != 0) {
    ByteOffset = resolveFromLineCol(Opts.Line, Opts.Col, SourceBuf.get());
  }

  if (Opts.EndLine != 0) {
    Opts.Length = resolveFromLineCol(Opts.EndLine, Opts.EndCol, SourceBuf.get()) -
      ByteOffset;
  }

  bool compilerArgsAreClang = false;

  sourcekitd_object_t Req = sourcekitd_request_dictionary_create(nullptr,
                                                                 nullptr, 0);
  ActiveRequest = Opts.Request;
  switch (Opts.Request) {
  case SourceKitRequest::None:
    llvm::errs() << "request is not set\n";
    // FIXME: This non-zero return value is not propagated as an exit code.
    //        In other words, despite returning 1 here, the program still exits
    //        with a zero (successful) exit code.
    return 1;

  case SourceKitRequest::GlobalConfiguration:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestGlobalConfiguration);

    for (auto &Opt : Opts.RequestOptions) {
      auto KeyValue = StringRef(Opt).split('=');
      std::string KeyStr("key.");
      KeyStr.append(KeyValue.first.str());
      sourcekitd_uid_t Key = sourcekitd_uid_get_from_cstr(KeyStr.c_str());

      int64_t Value = 0;
      KeyValue.second.getAsInteger(0, Value);
      sourcekitd_request_dictionary_set_int64(Req, Key, Value);
    }
    break;

  case SourceKitRequest::ProtocolVersion:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestProtocolVersion);
    break;
  
  case SourceKitRequest::CompilerVersion:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCompilerVersion);
    break;

  case SourceKitRequest::DemangleNames:
    prepareDemangleRequest(Req, Opts);
    break;

  case SourceKitRequest::MangleSimpleClasses:
    prepareMangleRequest(Req, Opts);
    break;

  case SourceKitRequest::EnableCompileNotifications: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestEnableCompileNotifications);
    int64_t value = 1;
    for (auto &Opt : Opts.RequestOptions) {
      auto KeyValue = StringRef(Opt).split('=');
      if (KeyValue.first == "value") {
        KeyValue.second.getAsInteger(0, value);
      } else {
        llvm::errs() << "unknown parameter '" << KeyValue.first
                     << "' in -req-opts";
        return 1;
      }
    }
    sourcekitd_request_dictionary_set_int64(Req, KeyValue, value);
    break;
  }

  case SourceKitRequest::Index:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestIndex);
    break;

  case SourceKitRequest::CodeComplete:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCodeComplete);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    // Default to sort by name.
    Opts.RequestOptions.insert(Opts.RequestOptions.begin(), "sort.byname=1");
    addRequestOptions(Req, Opts, KeyCodeCompleteOptions, "key.codecomplete.");
    break;

  case SourceKitRequest::CodeCompleteOpen:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestCodeCompleteOpen);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    addRequestOptions(Req, Opts, KeyCodeCompleteOptions, "key.codecomplete.");
    break;

  case SourceKitRequest::CodeCompleteClose:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestCodeCompleteClose);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    break;

  case SourceKitRequest::CodeCompleteUpdate:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestCodeCompleteUpdate);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    addRequestOptions(Req, Opts, KeyCodeCompleteOptions, "key.codecomplete.");
    break;

  case SourceKitRequest::CodeCompleteCacheOnDisk:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestCodeCompleteCacheOnDisk);
    sourcekitd_request_dictionary_set_string(Req, KeyName,
                                             Opts.CachePath.c_str());
    break;

  case SourceKitRequest::CodeCompleteSetPopularAPI: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestCodeCompleteSetPopularAPI);

    auto addPopularList = [&Req](StringRef filename, sourcekitd_uid_t key) {
      std::vector<std::string> names;
      if (readPopularAPIList(filename, names))
        return true;

      sourcekitd_object_t popular = sourcekitd_request_array_create(nullptr, 0);
      for (auto name : names)
        sourcekitd_request_array_set_string(popular, SOURCEKITD_ARRAY_APPEND,
                                            name.c_str());
      sourcekitd_request_dictionary_set_value(Req, key, popular);
      return false;
    };

    for (auto &Opt : Opts.RequestOptions) {
      auto KeyValue = StringRef(Opt).split('=');
      auto key = llvm::StringSwitch<sourcekitd_uid_t>(KeyValue.first)
        .Case("popular", KeyPopular)
        .Case("unpopular", KeyUnpopular)
        .Default(nullptr);
      if (!key) {
        llvm::errs() << "invalid key '" << KeyValue.first << "' in -req-opts\n";
        return 1;
      }

      if (addPopularList(KeyValue.second, key))
        return 1;
    }

    break;
  }

  case SourceKitRequest::TypeContextInfo:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestTypeContextInfo);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    addRequestOptions(Req, Opts, KeyTypeContextInfoOptions,
                      "key.typecontextinfo.");
    break;

  case SourceKitRequest::ConformingMethodList:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestConformingMethodList);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    addRequestOptionsDirect(Req, Opts);
    break;

  case SourceKitRequest::CursorInfo:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCursorInfo);
    if (Opts.CollectActionables) {
      sourcekitd_request_dictionary_set_int64(Req, KeyRetrieveRefactorActions, 1);
    }
    if (Opts.Length) {
      sourcekitd_request_dictionary_set_int64(Req, KeyLength, Opts.Length);
    }
    if (!Opts.USR.empty()) {
      sourcekitd_request_dictionary_set_string(Req, KeyUSR, Opts.USR.c_str());
    } else {
      sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    }
    addRequestOptionsDirect(Req, Opts);
    break;
  case SourceKitRequest::RangeInfo: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestRangeInfo);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    auto Length = Opts.Length;
    if (Opts.Length == 0 && Opts.EndLine > 0) {
      auto EndOff = resolveFromLineCol(Opts.EndLine, Opts.EndCol, SourceFile,
                                       Opts.VFSFiles);
      Length = EndOff - ByteOffset;
    }
    sourcekitd_request_dictionary_set_int64(Req, KeyLength, Length);
    break;
  }

  case SourceKitRequest::CollectExpresstionType: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCollectExpressionType);
    addRequestOptionsDirect(Req, Opts);
    break;
  }

  case SourceKitRequest::CollectVariableType: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestCollectVariableType);
    if (Opts.Length) {
      sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
      sourcekitd_request_dictionary_set_int64(Req, KeyLength, Opts.Length);
    }
    addRequestOptionsDirect(Req, Opts);
    break;
  }

#define SEMANTIC_REFACTORING(KIND, NAME, ID)                                   \
  case SourceKitRequest::KIND:                                                 \
    setRefactoringFields(Req, Opts, KindRefactoring##KIND, SourceBuf.get());   \
    break;
#include "swift/IDE/RefactoringKinds.def"

  case SourceKitRequest::MarkupToXML: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestMarkupToXML);
    break;
  }
  case SourceKitRequest::NameTranslation: {
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestNameTranslation);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    StringRef BaseName;
    llvm::SmallVector<StringRef, 4> ArgPieces;
    sourcekitd_uid_t ArgName;
    if (!Opts.SwiftName.empty()) {
      sourcekitd_request_dictionary_set_uid(Req, KeyNameKind, KindNameSwift);
      ArgName = KeyArgNames;
      StringRef Text(Opts.SwiftName);
      auto ArgStart = Text.find_first_of('(');
      if (ArgStart == StringRef::npos) {
        BaseName = Text;
      } else {
        BaseName = Text.substr(0, ArgStart);
        auto ArgEnd = Text.find_last_of(')');
        if (ArgEnd == StringRef::npos) {
          llvm::errs() << "Swift name is malformed.\n";
          return 1;
        }
        StringRef AllArgs = Text.substr(ArgStart + 1, ArgEnd - ArgStart - 1);
        AllArgs.split(ArgPieces, ':');
        if (!ArgPieces.empty()) {
          if (!ArgPieces.back().empty()) {
            llvm::errs() << "Swift name is malformed.\n";
            return 1;
          }
          ArgPieces.pop_back();
        }
      }
    } else if (!Opts.ObjCName.empty()) {
      sourcekitd_request_dictionary_set_uid(Req, KeyNameKind, KindNameObjc);
      BaseName = Opts.ObjCName;
      ArgName = KeySelectorPieces;
    } else if (!Opts.ObjCSelector.empty()) {
      sourcekitd_request_dictionary_set_uid(Req, KeyNameKind, KindNameObjc);
      StringRef Name(Opts.ObjCSelector);
      Name.split(ArgPieces, ':');
      if (ArgPieces.back().empty())
        ArgPieces.pop_back();
      ArgName = KeySelectorPieces;
    } else {
      llvm::errs() << "must specify either -swift-name or -objc-name or -objc-selector\n";
      return 1;
    }
    if (!BaseName.empty()) {
      std::string S = BaseName.str();
      sourcekitd_request_dictionary_set_string(Req, KeyBaseName, S.c_str());
    }
    if (!ArgPieces.empty()) {
      sourcekitd_object_t Arr = sourcekitd_request_array_create(nullptr, 0);
      for (StringRef A : ArgPieces) {
        std::string S = A.str();
        sourcekitd_request_array_set_string(Arr, SOURCEKITD_ARRAY_APPEND,
                                            S.c_str());
      }
      sourcekitd_request_dictionary_set_value(Req, ArgName, Arr);
    }
    break;
  }

  case SourceKitRequest::RelatedIdents:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestRelatedIdents);
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    break;

  case SourceKitRequest::SyntaxMap:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, true);
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false);
    sourcekitd_request_dictionary_set_uid(Req, KeySyntaxTreeTransferMode,
                                          KindSyntaxTreeOff);
    sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema);
    break;

  case SourceKitRequest::Structure:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false);
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, true);
    sourcekitd_request_dictionary_set_uid(Req, KeySyntaxTreeTransferMode,
                                          KindSyntaxTreeOff);
    sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema);
    break;

  case SourceKitRequest::Format:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false);
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false);
    sourcekitd_request_dictionary_set_uid(Req, KeySyntaxTreeTransferMode,
                                          KindSyntaxTreeOff);
    sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema);
    break;

  case SourceKitRequest::ExpandPlaceholder:
    if (Opts.Length) {
      // Single placeholder by location.
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorExpandPlaceholder);
      sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
      sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
      sourcekitd_request_dictionary_set_int64(Req, KeyLength, Opts.Length);
    } else {
      if (ByteOffset) {
        llvm::errs() << "Missing '-length <number>'\n";
        return 1;
      }
      // Expand all placeholders.
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
      sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
      sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false);
      sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false);
      sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema);
    }
    break;

  case SourceKitRequest::SyntaxTree:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false);
    sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false);
    sourcekitd_request_dictionary_set_uid(Req, KeySyntaxTreeTransferMode,
                                          KindSyntaxTreeFull);
    sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, true);
    break;

  case SourceKitRequest::DocInfo:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestDocInfo);
    break;

  case SourceKitRequest::SemanticInfo:
    InitOpts.UsedSema = true;
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    break;

  case SourceKitRequest::Open:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    addRequestOptionsDirect(Req, Opts);
    break;

  case SourceKitRequest::Close:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorClose);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    break;

  case SourceKitRequest::Edit:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestEditorReplaceText);
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
    sourcekitd_request_dictionary_set_int64(Req, KeyLength, Opts.Length);
    sourcekitd_request_dictionary_set_string(Req, KeySourceText,
                                       Opts.ReplaceText.getValue().c_str());
    addRequestOptionsDirect(Req, Opts);
    break;

  case SourceKitRequest::PrintAnnotations:
    return printAnnotations();
  case SourceKitRequest::PrintDiags:
    return printDiags();
  case SourceKitRequest::ExtractComment:
    if (Opts.SourceFile.empty()) {
      llvm::errs() << "Missing '<source-file>' \n";
      return 1;
    }
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestEditorExtractTextFromComment);
    break;

  case SourceKitRequest::InterfaceGen:
  case SourceKitRequest::InterfaceGenOpen:
    sourcekitd_request_dictionary_set_int64(Req, KeySynthesizedExtension,
                                            Opts.SynthesizedExtensions);
    if (Opts.ModuleName.empty() && Opts.HeaderPath.empty() &&
        Opts.SourceFile.empty() && Opts.USR.empty()) {
      llvm::errs() << "Missing '-module <module name>' or '-header <path>'" <<
        "or '<source-file>' or '-usr <USR>' \n";
      return 1;
    }
    if (!Opts.ModuleName.empty()) {
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                            RequestEditorOpenInterface);
    } else if (!Opts.USR.empty()) {
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                            RequestEditorOpenSwiftTypeInterface);
    } else if (!Opts.SourceFile.empty()) {
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                            RequestEditorOpenSwiftSourceInterface);
    } else {
      if (Opts.UsingSwiftArgs)
          sourcekitd_request_dictionary_set_int64(Req, KeyUsingSwiftArgs, true);
      else
        compilerArgsAreClang = true;
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                            RequestEditorOpenHeaderInterface);
    }

    sourcekitd_request_dictionary_set_string(Req, KeyName, getInterfaceGenDocumentName().c_str());
    if (!Opts.ModuleGroupName.empty())
      sourcekitd_request_dictionary_set_string(Req, KeyGroupName,
                                               Opts.ModuleGroupName.c_str());
    if (!Opts.InterestedUSR.empty())
      sourcekitd_request_dictionary_set_string(Req, KeyInterestedUSR,
                                               Opts.InterestedUSR.c_str());
    if (!Opts.USR.empty())
      sourcekitd_request_dictionary_set_string(Req, KeyUSR, Opts.USR.c_str());
    break;

  case SourceKitRequest::FindInterfaceDoc:
    if (Opts.ModuleName.empty()) {
      llvm::errs() << "Missing '-module <module name>'\n";
      return 1;
    }
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorFindInterfaceDoc);
    break;

  case SourceKitRequest::FindUSR:
    if (Opts.USR.empty()) {
      llvm::errs() << "Missing '-usr <USR string>'\n";
      return 1;
    }
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorFindUSR);
    sourcekitd_request_dictionary_set_string(Req, KeyUSR, Opts.USR.c_str());
    break;

  case SourceKitRequest::ModuleGroups:
    if (Opts.ModuleName.empty()) {
      llvm::errs() << "Missing '-module <module name>'\n";
      return 1;
    }
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestModuleGroups);
    break;

  case SourceKitRequest::FindLocalRenameRanges:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestFindLocalRenameRanges);
    sourcekitd_request_dictionary_set_int64(Req, KeyLine, Opts.Line);
    sourcekitd_request_dictionary_set_int64(Req, KeyColumn, Opts.Col);
    sourcekitd_request_dictionary_set_int64(Req, KeyLength, Opts.Length);
    break;

  case SourceKitRequest::SyntacticRename:
  case SourceKitRequest::FindRenameRanges: {
    if (Opts.Request == SourceKitRequest::SyntacticRename) {
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestSyntacticRename);
    } else {
      sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestFindRenameRanges);
    }
    if (Opts.RenameSpecPath.empty()) {
      llvm::errs() << "Missing '-rename-spec <file path>'\n";
      return 1;
    }
    auto Buffer =
        getBufferForFilename(Opts.RenameSpecPath, Opts.VFSFiles)->getBuffer();
    char *Err = nullptr;
    auto RenameSpec = sourcekitd_request_create_from_yaml(Buffer.data(), &Err);
    if (!RenameSpec) {
      assert(Err);
      llvm::errs() << Err;
      free(Err);
      return 1;
    }
    sourcekitd_request_dictionary_set_value(Req, KeyRenameLocations, RenameSpec);
    break;
  }
  case SourceKitRequest::Statistics:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestStatistics);
    break;

  case SourceKitRequest::DependencyUpdated:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
                                          RequestDependencyUpdated);
    break;
  case SourceKitRequest::Diagnostics:
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestDiagnostics);
    break;

  case SourceKitRequest::Compile:
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCompile);
    break;

  case SourceKitRequest::CompileClose:
    sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
    sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCompileClose);
    break;
  }

  if (!SourceFile.empty()) {
    if (Opts.PassAsSourceText) {
      auto Buf = getBufferForFilename(SourceFile, Opts.VFSFiles);
      sourcekitd_request_dictionary_set_string(Req, KeySourceText,
                                               Buf->getBufferStart());
    }
    sourcekitd_request_dictionary_set_string(Req, KeySourceFile,
                                             SourceFile.c_str());
  }

  if (Opts.SourceText) {
    sourcekitd_request_dictionary_set_string(Req, KeySourceText,
                                             Opts.SourceText->c_str());
    sourcekitd_request_dictionary_set_string(Req, KeySourceFile,
                                             SemaName.c_str());
  }

  if (!Opts.CompilerArgs.empty() ||
      !Opts.ModuleCachePath.empty() ||
      Opts.DisableImplicitConcurrencyModuleImport) {
    sourcekitd_object_t Args = sourcekitd_request_array_create(nullptr, 0);
    if (!Opts.ModuleCachePath.empty()) {
      if (compilerArgsAreClang) {
        // We need -fmodules or else the clang argument parsing does not honour
        // -fmodules-cache-path. In reality, the swift ClangImporter will always
        // enable modules when importing, so this should only impact the
        // clang argument parsing. This is needed even if the header doesn't
        // use modules, since Swift itself will import its shims module, and
        // that needs to honour the -module-cache-path option when testing.
        sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, "-fmodules");
        std::string opt = "-fmodules-cache-path=" + Opts.ModuleCachePath;
        sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, opt.c_str());
      } else {
        sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, "-module-cache-path");
        sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, Opts.ModuleCachePath.c_str());
      }
    }
    if (Opts.DisableImplicitConcurrencyModuleImport && !compilerArgsAreClang) {
      sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND,
                                          "-Xfrontend");
      sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND,
          "-disable-implicit-concurrency-module-import");
    }

    for (auto Arg : Opts.CompilerArgs)
      sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, Arg);
    sourcekitd_request_dictionary_set_value(Req, KeyCompilerArgs, Args);
    sourcekitd_request_release(Args);
  }

  if (!Opts.ModuleName.empty()) {
    sourcekitd_request_dictionary_set_string(Req, KeyModuleName,
                                             Opts.ModuleName.c_str());
  }
  if (!Opts.HeaderPath.empty()) {
    sourcekitd_request_dictionary_set_string(Req, KeyFilePath,
                                             Opts.HeaderPath.c_str());
  }
  if (Opts.CancelOnSubsequentRequest.hasValue()) {
    sourcekitd_request_dictionary_set_int64(Req, KeyCancelOnSubsequentRequest,
                                            *Opts.CancelOnSubsequentRequest);
  }
  if (Opts.SimulateLongRequest.hasValue()) {
    sourcekitd_request_dictionary_set_int64(Req, KeySimulateLongRequest,
                                            *Opts.SimulateLongRequest);
  }

  if (!Opts.SwiftVersion.empty()) {
    if (Opts.PassVersionAsString) {
      sourcekitd_request_dictionary_set_string(Req, KeySwiftVersion,
                                               Opts.SwiftVersion.c_str());
    } else {
      unsigned ver;
      if (StringRef(Opts.SwiftVersion).getAsInteger(10, ver)) {
        llvm::errs() << "error: expected integer for 'swift-version'\n";
        return true;
      }
      sourcekitd_request_dictionary_set_int64(Req, KeySwiftVersion, ver);
    }
  }

  if (Opts.VFSName) {
    sourcekitd_request_dictionary_set_string(Req, KeyVFSName, Opts.VFSName->c_str());
  }
  if (!Opts.VFSFiles.empty()) {
    sourcekitd_object_t files = sourcekitd_request_array_create(nullptr, 0);
    for (auto &NameAndTarget : Opts.VFSFiles) {
      sourcekitd_object_t file = sourcekitd_request_dictionary_create(nullptr, nullptr, 0);
      sourcekitd_request_dictionary_set_string(file, KeyName, NameAndTarget.first().data());

      if (NameAndTarget.second.passAsSourceText) {
        auto content = getBufferForFilename(NameAndTarget.first(), Opts.VFSFiles);
        sourcekitd_request_dictionary_set_string(file, KeySourceText,  content->getBufferStart());
      } else {
        sourcekitd_request_dictionary_set_string(file, KeySourceFile,  NameAndTarget.second.path.c_str());
      }
      sourcekitd_request_array_set_value(files, SOURCEKITD_ARRAY_APPEND, file);
    }
    sourcekitd_object_t vfsOpts = sourcekitd_request_dictionary_create(nullptr, nullptr, 0);
    sourcekitd_request_dictionary_set_value(vfsOpts, KeyFiles, files);
    sourcekitd_request_dictionary_set_value(Req, KeyVFSOptions, vfsOpts);
    sourcekitd_request_release(vfsOpts);
    sourcekitd_request_release(files);
  }

  int64_t BeforeInstructions;
  if (Opts.measureInstructions)
    BeforeInstructions = getSourceKitInstructionCount();

  if (!Opts.isAsyncRequest) {
    sourcekitd_response_t Resp = sendRequestSync(Req, Opts);

    if (Opts.measureInstructions) {
      int64_t AfterInstructions = getSourceKitInstructionCount();
      llvm::errs() << "request instructions: "
                   << (AfterInstructions - BeforeInstructions);
    }

    sourcekitd_request_release(Req);
    return handleResponse(Resp, Opts, SemaName, std::move(SourceBuf),
                          &InitOpts)
               ? 1
               : 0;
  } else {
#if SOURCEKITD_HAS_BLOCKS
    AsyncResponseInfo info;
    info.options = Opts;
    info.sourceFilename = std::move(SemaName);
    info.sourceBuffer = std::move(SourceBuf);
    unsigned respIndex = asyncResponses.size();
    asyncResponses.push_back(std::move(info));

    if (Opts.PrintRequest)
      sourcekitd_request_description_dump(Req);

    sourcekitd_send_request(Req, &asyncResponses[respIndex].requestHandle,
                            ^(sourcekitd_response_t resp) {
                              auto &info = asyncResponses[respIndex];
                              info.response = resp;
                              sourcekitd_request_handle_dispose(
                                  info.requestHandle);
                              info.semaphore.signal(); // Ready to be handled!
                            });

#else
    llvm::report_fatal_error(
        "-async not supported when sourcekitd is built without blocks support");
#endif

    if (Opts.measureInstructions) {
      int64_t AfterInstructions = getSourceKitInstructionCount();
      llvm::errs() << "request instructions: "
                   << (AfterInstructions - BeforeInstructions);
    }

    sourcekitd_request_release(Req);
    return 0;
  }
}