//===--- Requests.cpp -----------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "DictionaryKeys.h"
#include "sourcekitd/CodeCompletionResultsArray.h"
#include "sourcekitd/DocStructureArray.h"
#include "sourcekitd/DocSupportAnnotationArray.h"
#include "sourcekitd/TokenAnnotationsArray.h"

#include "SourceKit/Core/Context.h"
#include "SourceKit/Core/LangSupport.h"
#include "SourceKit/Core/NotificationCenter.h"
#include "SourceKit/Support/Concurrency.h"
#include "SourceKit/Support/Logging.h"
#include "SourceKit/Support/UIdent.h"
#include "SourceKit/SwiftLang/Factory.h"

#include "swift/Demangling/ManglingMacros.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Basic/Mangler.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h"
#include <mutex>

// FIXME: Portability.
#include <dispatch/dispatch.h>

using namespace sourcekitd;
using namespace SourceKit;

namespace {
class LazySKDUID {
  const char *Name;
  mutable std::atomic<sourcekitd_uid_t> UID { nullptr };
public:
  LazySKDUID(const char *Name) : Name(Name) { }

  sourcekitd_uid_t get() const {
    sourcekitd_uid_t UIDValue = UID;
    if (!UIDValue)
      UID = SKDUIDFromUIdent(UIdent(Name));
    return UID;
  }

  operator sourcekitd_uid_t() const {
    return get();
  }

  StringRef str() const {
    return StringRef(Name);
  }
};
} // anonymous namespace

#define REQUEST(NAME, CONTENT) static LazySKDUID Request##NAME(CONTENT);
#define KIND(NAME, CONTENT) static LazySKDUID Kind##NAME(CONTENT);
#include "SourceKit/Core/ProtocolUIDs.def"

static void onDocumentUpdateNotification(StringRef DocumentName) {
  static UIdent DocumentUpdateNotificationUID(
      "source.notification.editor.documentupdate");

  ResponseBuilder RespBuilder;
  auto Dict = RespBuilder.getDictionary();
  Dict.set(KeyNotification, DocumentUpdateNotificationUID);
  Dict.set(KeyName, DocumentName);

  sourcekitd::postNotification(RespBuilder.createResponse());
}

static SourceKit::Context *GlobalCtx = nullptr;

void sourcekitd::initialize() {
  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllAsmParsers();

  GlobalCtx = new SourceKit::Context(sourcekitd::getRuntimeLibPath(),
                                     SourceKit::createSwiftLangSupport);
  GlobalCtx->getNotificationCenter().addDocumentUpdateNotificationReceiver(
    onDocumentUpdateNotification);
}
void sourcekitd::shutdown() {
  delete GlobalCtx;
  GlobalCtx = nullptr;
}

static SourceKit::Context &getGlobalContext() {
  assert(GlobalCtx);
  return *GlobalCtx;
}

static sourcekitd_response_t demangleNames(ArrayRef<const char *> MangledNames,
                                           bool Simplified);

static sourcekitd_response_t
mangleSimpleClassNames(ArrayRef<std::pair<StringRef, StringRef>> ModuleClassPairs);

static sourcekitd_response_t indexSource(StringRef Filename,
                                         ArrayRef<const char *> Args,
                                         StringRef KnownHash);

static sourcekitd_response_t reportDocInfo(llvm::MemoryBuffer *InputBuf,
                                           StringRef ModuleName,
                                           ArrayRef<const char *> Args);

static void reportCursorInfo(const CursorInfo &Info, ResponseReceiver Rec);

static void reportRangeInfo(const RangeInfo &Info, ResponseReceiver Rec);

static void reportNameInfo(const NameTranslatingInfo &Info, ResponseReceiver Rec);

static void findRelatedIdents(StringRef Filename,
                              int64_t Offset,
                              bool CancelOnSubsequentRequest,
                              ArrayRef<const char *> Args,
                              ResponseReceiver Rec);

static sourcekitd_response_t codeComplete(llvm::MemoryBuffer *InputBuf,
                                          int64_t Offset,
                                          ArrayRef<const char *> Args);

static sourcekitd_response_t codeCompleteOpen(StringRef name,
                                              llvm::MemoryBuffer *InputBuf,
                                              int64_t Offset,
                                              Optional<RequestDict> optionsDict,
                                              ArrayRef<const char *> Args);

static sourcekitd_response_t
codeCompleteUpdate(StringRef name, int64_t Offset,
                   Optional<RequestDict> optionsDict);

static sourcekitd_response_t codeCompleteClose(StringRef name, int64_t Offset);

static sourcekitd_response_t
editorOpen(StringRef Name, llvm::MemoryBuffer *Buf, bool EnableSyntaxMap,
           bool EnableStructure, bool EnableDiagnostics, bool SyntacticOnly,
           ArrayRef<const char *> Args);

static sourcekitd_response_t
editorOpenInterface(StringRef Name, StringRef ModuleName,
                    Optional<StringRef> Group, ArrayRef<const char *> Args,
                    bool SynthesizedExtensions,
                    Optional<StringRef> InterestedUSR);

static sourcekitd_response_t
editorOpenHeaderInterface(StringRef Name, StringRef HeaderName,
                          ArrayRef<const char *> Args,
                          bool UsingSwiftArgs,
                          bool SynthesizedExtensions,
                          Optional<unsigned> swiftVersion);

static void
editorOpenSwiftSourceInterface(StringRef Name, StringRef SourceName,
                               ArrayRef<const char *> Args,
                               ResponseReceiver Rec);

static void
editorOpenSwiftTypeInterface(StringRef TypeUsr, ArrayRef<const char *> Args,
                             ResponseReceiver Rec);

static sourcekitd_response_t editorExtractTextFromComment(StringRef Source);

static sourcekitd_response_t editorConvertMarkupToXML(StringRef Source);

static sourcekitd_response_t
editorClose(StringRef Name, bool RemoveCache);

static sourcekitd_response_t
editorReplaceText(StringRef Name, llvm::MemoryBuffer *Buf, unsigned Offset,
                  unsigned Length, bool EnableSyntaxMap, bool EnableStructure,
                  bool EnableDiagnostics, bool SyntacticOnly);

static void
editorApplyFormatOptions(StringRef Name, RequestDict &FmtOptions);

static sourcekitd_response_t
editorFormatText(StringRef Name, unsigned Line, unsigned Length);

static sourcekitd_response_t
editorExpandPlaceholder(StringRef Name, unsigned Offset, unsigned Length);

static sourcekitd_response_t
editorFindUSR(StringRef DocumentName, StringRef USR);

static sourcekitd_response_t
editorFindInterfaceDoc(StringRef ModuleName, ArrayRef<const char *> Args);

static sourcekitd_response_t
editorFindModuleGroups(StringRef ModuleName, ArrayRef<const char *> Args);

static bool isSemanticEditorDisabled();

static void fillDictionaryForDiagnosticInfo(
    ResponseBuilder::Dictionary Elem, const DiagnosticEntryInfoBase &Info);

static void handleRequestImpl(sourcekitd_object_t Req,
                              ResponseReceiver Receiver);

void sourcekitd::handleRequest(sourcekitd_object_t Req,
                               ResponseReceiver Receiver) {
  LOG_SECTION("handleRequest-before", InfoHighPrio) {
    sourcekitd::printRequestObject(Req, Log->getOS());
  }

  handleRequestImpl(Req, [Receiver](sourcekitd_response_t Resp) {
    LOG_SECTION("handleRequest-after", InfoHighPrio) {
      // Responses are big, print them out with info medium priority.
      if (Logger::isLoggingEnabledForLevel(Logger::Level::InfoMediumPrio))
        sourcekitd::printResponse(Resp, Log->getOS());
    }

    Receiver(Resp);
  });
}

static std::unique_ptr<llvm::MemoryBuffer>
getInputBufForRequest(Optional<StringRef> SourceFile,
                      Optional<StringRef> SourceText,
                      llvm::SmallString<64> &ErrBuf) {

  std::unique_ptr<llvm::MemoryBuffer> InputBuf;

  if (SourceText.hasValue()) {
    StringRef BufName;
    if (SourceFile.hasValue())
      BufName = *SourceFile;
    else
      BufName = "<input>";
    InputBuf = llvm::MemoryBuffer::getMemBuffer(*SourceText, BufName);

  } else if (SourceFile.hasValue()) {
    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
      llvm::MemoryBuffer::getFile(*SourceFile);
    if (FileBufOrErr) {
      InputBuf = std::move(FileBufOrErr.get());
    } else {
      llvm::raw_svector_ostream OSErr(ErrBuf);
      OSErr << "error opening input file '" << *SourceFile << "' ("
            << FileBufOrErr.getError().message() << ')';
      return nullptr;
    }
  } else {
    InputBuf = llvm::MemoryBuffer::getNewMemBuffer(0, "<input>");
  }

  return InputBuf;
}


static void
handleSemanticRequest(RequestDict Req,
                      ResponseReceiver Receiver,
                      sourcekitd_uid_t ReqUID,
                      Optional<StringRef> SourceFile,
                      Optional<StringRef> SourceText,
                      ArrayRef<const char *> Args);

void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
  RequestDict Req(ReqObj);
  sourcekitd_uid_t ReqUID = Req.getUID(KeyRequest);
  if (!ReqUID)
    return Rec(createErrorRequestInvalid("missing 'key.request' with UID value"));

  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 == RequestCrashWithExit) {
    // 'exit' has the same effect as crashing but without the crash log.
    ::exit(1);
  }

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

  // Just accept 'source.request.buildsettings.register' for now, don't do
  // anything else.
  // FIXME: Heavy WIP here.
  if (ReqUID == RequestBuildSettingsRegister) {
    return Rec(ResponseBuilder().createResponse());
  }

  Optional<StringRef> SourceFile = Req.getString(KeySourceFile);
  Optional<StringRef> SourceText = Req.getString(KeySourceText);

  llvm::SmallString<64> ErrBuf;

  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, 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, 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);
    int64_t SyntacticOnly = false;
    Req.getInt64(KeySyntacticOnly, SyntacticOnly, /*isOptional=*/true);
    return Rec(editorOpen(*Name, InputBuf.get(), EnableSyntaxMap, EnableStructure,
                          EnableDiagnostics, SyntacticOnly, Args));
  }
  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, 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);
    return Rec(editorReplaceText(*Name, InputBuf.get(), Offset, Length,
                                 EnableSyntaxMap, EnableStructure,
                                 EnableDiagnostics, SyntacticOnly));
  }
  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);
    Optional<int64_t> swiftVerVal = Req.getOptionalInt64(KeySwiftVersion);
    Optional<unsigned> swiftVer;
    if (swiftVerVal.hasValue())
      swiftVer = *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, 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 == 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;

      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 (!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);
  SemaQueue.dispatch(
    [ReqObj, Rec, ReqUID, SourceFile, SourceText, Args] {
      RequestDict Req(ReqObj);
      handleSemanticRequest(Req, Rec, ReqUID, SourceFile, SourceText, Args);
      sourcekitd_request_release(ReqObj);
    },
    /*isStackDeep=*/true);
}

static void
handleSemanticRequest(RequestDict Req,
                      ResponseReceiver Rec,
                      sourcekitd_uid_t ReqUID,
                      Optional<StringRef> SourceFile,
                      Optional<StringRef> SourceText,
                      ArrayRef<const char *> Args) {

  llvm::SmallString<64> ErrBuf;

  if (ReqUID == RequestCodeComplete) {
    std::unique_ptr<llvm::MemoryBuffer>
    InputBuf = getInputBufForRequest(SourceFile, SourceText, ErrBuf);
    if (!InputBuf)
      return Rec(createErrorRequestFailed(ErrBuf.c_str()));
    int64_t Offset;
    if (Req.getInt64(KeyOffset, Offset, /*isOptional=*/false))
      return Rec(createErrorRequestInvalid("missing 'key.offset'"));
    return Rec(codeComplete(InputBuf.get(), Offset, Args));
  }

  if (ReqUID == RequestCodeCompleteOpen) {
    std::unique_ptr<llvm::MemoryBuffer> InputBuf =
        getInputBufForRequest(SourceFile, SourceText, ErrBuf);
    if (!InputBuf)
      return Rec(createErrorRequestFailed(ErrBuf.c_str()));
    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'"));
    Optional<RequestDict> options = Req.getDictionary(KeyCodeCompleteOptions);
    return Rec(codeCompleteOpen(*Name, InputBuf.get(), Offset, options, Args));
  }

  if (ReqUID == RequestCodeCompleteUpdate) {
    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'"));
    Optional<RequestDict> options = Req.getDictionary(KeyCodeCompleteOptions);
    return Rec(codeCompleteUpdate(*Name, Offset, options));
  }

  if (!SourceFile.hasValue())
    return Rec(createErrorRequestInvalid("missing 'key.sourcefile'"));

  if (ReqUID == RequestIndex) {
    StringRef Hash;
    Optional<StringRef> HashOpt = Req.getString(KeyHash);
    if (HashOpt.hasValue()) Hash = *HashOpt;
    return Rec(indexSource(*SourceFile, Args, Hash));
  }

  if (isSemanticEditorDisabled())
      return Rec(createErrorRequestFailed("semantic editor is disabled"));

  if (ReqUID == RequestCursorInfo) {
    LangSupport &Lang = getGlobalContext().getSwiftLangSupport();

    // For backwards compatibility, the default is 1.
    int64_t CancelOnSubsequentRequest = 1;
    Req.getInt64(KeyCancelOnSubsequentRequest, CancelOnSubsequentRequest,
                 /*isOptional=*/true);

    int64_t Offset;
    if (!Req.getInt64(KeyOffset, Offset, /*isOptional=*/false)) {
      int64_t Length = 0;
      Req.getInt64(KeyLength, Length, /*isOptional=*/true);
      int64_t Actionables = false;
      Req.getInt64(KeyActionable, Actionables, /*isOptional=*/true);
      return Lang.getCursorInfo(
          *SourceFile, Offset, Length, Actionables, CancelOnSubsequentRequest,
          Args, [Rec](const CursorInfo &Info) { reportCursorInfo(Info, Rec); });
    }
    if (auto USR = Req.getString(KeyUSR)) {
      return Lang.getCursorInfoFromUSR(
          *SourceFile, *USR, CancelOnSubsequentRequest, Args,
          [Rec](const CursorInfo &Info) { reportCursorInfo(Info, Rec); });
    }

    return Rec(createErrorRequestInvalid(
        "either 'key.offset' or 'key.usr' is required"));
  }

  if (ReqUID == RequestRangeInfo) {
    LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
    int64_t Offset;
    int64_t Length;
    // For backwards compatibility, the default is 1.
    int64_t CancelOnSubsequentRequest = 1;
    Req.getInt64(KeyCancelOnSubsequentRequest, CancelOnSubsequentRequest,
                 /*isOptional=*/true);
    if (!Req.getInt64(KeyOffset, Offset, /*isOptional=*/false)) {
      if (!Req.getInt64(KeyLength, Length, /*isOptional=*/false)) {
        return Lang.getRangeInfo(*SourceFile, Offset, Length,
                                 CancelOnSubsequentRequest, Args,
          [Rec](const RangeInfo &Info) { reportRangeInfo(Info, Rec); });
      }
    }

    return Rec(createErrorRequestInvalid(
      "'key.offset' or 'key.length' is required"));
  }

  if (ReqUID == RequestNameTranslation) {
    LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
    int64_t Offset;
    if (Req.getInt64(KeyOffset, Offset, /*isOptional=*/false)) {
      return Rec(createErrorRequestInvalid("'key.offset' is required"));
    }
    NameTranslatingInfo Input;
    auto NK = Req.getUID(KeyNameKind);
    if (!NK) {
      return Rec(createErrorRequestInvalid("'key.namekind' is required"));
    }
    if (NK == KindNameSwift.get())
      Input.NameKind = UIdent(KindNameSwift.str());
    else if (NK == KindNameObjc.get())
      Input.NameKind = UIdent(KindNameObjc.str());
    else
      return Rec(createErrorRequestInvalid("'key.namekind' is unrecognizable"));
    if (auto Base = Req.getString(KeyBaseName)) {
      Input.BaseName = Base.getValue();
    }
    llvm::SmallVector<const char*, 4> ArgParts;
    llvm::SmallVector<const char*, 4> Selectors;
    Req.getStringArray(KeyArgNames, ArgParts, true);
    Req.getStringArray(KeySelectorPieces, Selectors, true);
    if (!ArgParts.empty() && !Selectors.empty()) {
      return Rec(createErrorRequestInvalid("cannot specify 'key.selectorpieces' "
                                           "and 'key.argnames' at the same time"));
    }
    std::transform(ArgParts.begin(), ArgParts.end(),
                   std::back_inserter(Input.ArgNames),
                   [](const char *C) { return StringRef(C); });
    std::transform(Selectors.begin(), Selectors.end(),
                   std::back_inserter(Input.ArgNames),
                   [](const char *C) { return StringRef(C); });
    return Lang.getNameInfo(*SourceFile, Offset, Input, Args,
      [Rec](const NameTranslatingInfo &Info) { reportNameInfo(Info, Rec); });
  }

  if (ReqUID == RequestRelatedIdents) {
    int64_t Offset;
    if (Req.getInt64(KeyOffset, Offset, /*isOptional=*/false))
      return Rec(createErrorRequestInvalid("missing 'key.offset'"));

    // For backwards compatibility, the default is 1.
    int64_t CancelOnSubsequentRequest = 1;
    Req.getInt64(KeyCancelOnSubsequentRequest, CancelOnSubsequentRequest,
                 /*isOptional=*/true);

    return findRelatedIdents(*SourceFile, Offset, CancelOnSubsequentRequest,
                             Args, Rec);
  }

  {
    llvm::raw_svector_ostream OSErr(ErrBuf);
    OSErr << "unknown request: " << UIdentFromSKDUID(ReqUID).getName();
  }
  return Rec(createErrorRequestInvalid(ErrBuf.c_str()));
}

//===----------------------------------------------------------------------===//
// Index
//===----------------------------------------------------------------------===//

namespace {
class SKIndexingConsumer : public IndexingConsumer {
  struct Entity {
    UIdent Kind;
    ResponseBuilder::Dictionary Data;
    ResponseBuilder::Array Entities;
    ResponseBuilder::Array Related;
  };
  SmallVector<Entity, 6> EntitiesStack;

  struct Dependency {
    UIdent Kind;
    ResponseBuilder::Dictionary Data;
    ResponseBuilder::Array Dependencies;
  };
  SmallVector<Dependency, 6> DependenciesStack;

  ResponseBuilder::Dictionary TopDict;
  bool Cancelled = false;

public:
  std::string ErrorDescription;

  explicit SKIndexingConsumer(ResponseBuilder &RespBuilder) {
    TopDict = RespBuilder.getDictionary();

    // First in stack is the top-level "key.entities" container.
    EntitiesStack.push_back(
        { UIdent(),
          TopDict,
          ResponseBuilder::Array(),
          ResponseBuilder::Array() });

    DependenciesStack.push_back({UIdent(), TopDict, ResponseBuilder::Array() });
  }
  ~SKIndexingConsumer() override {
    assert(Cancelled ||
           (EntitiesStack.size() == 1 && DependenciesStack.size() == 1));
    (void) Cancelled;
  }

  void failed(StringRef ErrDescription) override;

  bool recordHash(StringRef Hash, bool isKnown) override;

  bool startDependency(UIdent Kind,
                       StringRef Name,
                       StringRef Path,
                       bool IsSystem,
                       StringRef Hash) override;

  bool finishDependency(UIdent Kind) override;

  bool startSourceEntity(const EntityInfo &Info) override;

  bool recordRelatedEntity(const EntityInfo &Info) override;

  bool finishSourceEntity(UIdent Kind) override;
};
} // end anonymous namespace

static sourcekitd_response_t indexSource(StringRef Filename,
                                         ArrayRef<const char *> Args,
                                         StringRef KnownHash) {
  ResponseBuilder RespBuilder;
  SKIndexingConsumer IdxConsumer(RespBuilder);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.indexSource(Filename, IdxConsumer, Args, KnownHash);

  if (!IdxConsumer.ErrorDescription.empty())
    return createErrorRequestFailed(IdxConsumer.ErrorDescription.c_str());

  return RespBuilder.createResponse();
}

void SKIndexingConsumer::failed(StringRef ErrDescription) {
  ErrorDescription = ErrDescription;
}

bool SKIndexingConsumer::recordHash(StringRef Hash, bool isKnown) {
  assert(!Hash.empty());
  TopDict.set(KeyHash, Hash);
  if (!isKnown) {
    // If the hash is known key.entities should be missing otherwise it should
    // exist, even as an empty array, so create it here.
    assert(EntitiesStack.size() == 1);
    Entity &Top = EntitiesStack.back();
    ResponseBuilder::Array &Arr = Top.Entities;
    assert(Arr.isNull());
    Arr = Top.Data.setArray(KeyEntities);
  }
  return true;
}

bool SKIndexingConsumer::startDependency(UIdent Kind,
                                         StringRef Name,
                                         StringRef Path,
                                         bool IsSystem,
                                         StringRef Hash) {
  Dependency &Parent = DependenciesStack.back();
  ResponseBuilder::Array &Arr = Parent.Dependencies;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyDependencies);

  auto Elem = Arr.appendDictionary();
  Elem.set(KeyKind, Kind);
  Elem.set(KeyName, Name);
  Elem.set(KeyFilePath, Path);
  if (IsSystem)
    Elem.setBool(KeyIsSystem, IsSystem);
  if (!Hash.empty())
    Elem.set(KeyHash, Hash);

  DependenciesStack.push_back({ Kind, Elem, ResponseBuilder::Array() });
  return true;
}

bool SKIndexingConsumer::finishDependency(UIdent Kind) {
  assert(DependenciesStack.back().Kind == Kind);
  DependenciesStack.pop_back();
  return true;
}

bool SKIndexingConsumer::startSourceEntity(const EntityInfo &Info) {
  Entity &Parent = EntitiesStack.back();
  ResponseBuilder::Array &Arr = Parent.Entities;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyEntities);

  auto Elem = Arr.appendDictionary();
  Elem.set(KeyKind, Info.Kind);
  if (!Info.Name.empty())
    Elem.set(KeyName, Info.Name);
  if (!Info.USR.empty())
    Elem.set(KeyUSR, Info.USR);
  if (Info.Line != 0) {
    assert(Info.Column != 0);
    Elem.set(KeyLine, Info.Line);
    Elem.set(KeyColumn, Info.Column);
  }
  if (!Info.Group.empty())
    Elem.set(KeyGroupName, Info.Group);

  if (!Info.ReceiverUSR.empty())
    Elem.set(KeyReceiverUSR, Info.ReceiverUSR);
  if (Info.IsDynamic)
    Elem.setBool(KeyIsDynamic, true);
  if (Info.IsTestCandidate)
    Elem.setBool(KeyIsTestCandidate, true);

  if (!Info.Attrs.empty()) {
    auto AttrArray = Elem.setArray(KeyAttributes);
    for (auto Attr : Info.Attrs) {
      auto AttrDict = AttrArray.appendDictionary();
      AttrDict.set(KeyAttribute, Attr);
    }
  }

  EntitiesStack.push_back({ Info.Kind, Elem, ResponseBuilder::Array(),
                            ResponseBuilder::Array()});
  return true;
}

bool SKIndexingConsumer::recordRelatedEntity(const EntityInfo &Info) {
  assert(EntitiesStack.size() > 1 && "Related entity at top-level ?");
  Entity &Parent = EntitiesStack.back();
  ResponseBuilder::Array &Arr = Parent.Related;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyRelated);

  auto Elem = Arr.appendDictionary();
  Elem.set(KeyKind, Info.Kind);
  if (!Info.Name.empty())
    Elem.set(KeyName, Info.Name);
  if (!Info.USR.empty())
    Elem.set(KeyUSR, Info.USR);
  if (Info.Line != 0) {
    assert(Info.Column != 0);
    Elem.set(KeyLine, Info.Line);
    Elem.set(KeyColumn, Info.Column);
  }

  return true;
}

bool SKIndexingConsumer::finishSourceEntity(UIdent Kind) {
  Entity &CurrEnt = EntitiesStack.back();
  assert(CurrEnt.Kind == Kind);
  (void) CurrEnt;
  EntitiesStack.pop_back();
  return true;
}

//===----------------------------------------------------------------------===//
// ReportDocInfo
//===----------------------------------------------------------------------===//

namespace {

class SKDocConsumer : public DocInfoConsumer {
  ResponseBuilder &RespBuilder;

  struct Entity {
    UIdent Kind;
    ResponseBuilder::Dictionary Data;
    ResponseBuilder::Array Entities;
    ResponseBuilder::Array Inherits;
    ResponseBuilder::Array Conforms;
    ResponseBuilder::Array Attrs;
  };
  SmallVector<Entity, 6> EntitiesStack;

  ResponseBuilder::Dictionary TopDict;
  ResponseBuilder::Array Diags;

  DocSupportAnnotationArrayBuilder AnnotationsBuilder;

  bool Cancelled = false;

  void addDocEntityInfoToDict(const DocEntityInfo &Info,
                              ResponseBuilder::Dictionary Dict);
public:
  std::string ErrorDescription;

  explicit SKDocConsumer(ResponseBuilder &RespBuilder)
      : RespBuilder(RespBuilder) {
    TopDict = RespBuilder.getDictionary();

    // First in stack is the top-level "key.entities" container.
    EntitiesStack.push_back(
        { UIdent(),
          TopDict,
          ResponseBuilder::Array(),
          ResponseBuilder::Array(),
          ResponseBuilder::Array(),
          ResponseBuilder::Array() });
  }
  ~SKDocConsumer() override {
    assert(Cancelled || EntitiesStack.size() == 1);
    (void) Cancelled;
  }

  sourcekitd_response_t createResponse() {
    TopDict.setCustomBuffer(KeyAnnotations,
        CustomBufferKind::DocSupportAnnotationArray,
        AnnotationsBuilder.createBuffer());
    return RespBuilder.createResponse();
  }

  void failed(StringRef ErrDescription) override;

  bool handleSourceText(StringRef Text) override;

  bool handleAnnotation(const DocEntityInfo &Info) override;

  bool startSourceEntity(const DocEntityInfo &Info) override;

  bool handleInheritsEntity(const DocEntityInfo &Info) override;
  bool handleConformsToEntity(const DocEntityInfo &Info) override;
  bool handleExtendsEntity(const DocEntityInfo &Info) override;

  bool handleAvailableAttribute(const AvailableAttrInfo &Info) override;

  bool finishSourceEntity(UIdent Kind) override;

  bool handleDiagnostic(const DiagnosticEntryInfo &Info) override;
};
} // end anonymous namespace

static bool isSwiftPrefixed(StringRef MangledName) {
  if (MangledName.size() < 2)
    return false;
  return MangledName[0] == '_' &&
         (MangledName[1] == 'T' || MangledName[1] == MANGLING_PREFIX_STR[1]);
}

static sourcekitd_response_t demangleNames(ArrayRef<const char *> MangledNames,
                                           bool Simplified) {
  swift::Demangle::DemangleOptions DemangleOptions;
  if (Simplified) {
    DemangleOptions =
      swift::Demangle::DemangleOptions::SimplifiedUIDemangleOptions();
  }

  auto getDemangledName = [&](StringRef MangledName) -> std::string {
    if (!isSwiftPrefixed(MangledName))
      return std::string(); // Not a mangled name

    std::string Result = swift::Demangle::demangleSymbolAsString(
        MangledName, DemangleOptions);

    if (Result == MangledName)
      return std::string(); // Not a mangled name

    return Result;
  };

  ResponseBuilder RespBuilder;
  auto Arr = RespBuilder.getDictionary().setArray(KeyResults);
  for (auto MangledName : MangledNames) {
    std::string Result = getDemangledName(MangledName);
    auto Entry = Arr.appendDictionary();
    Entry.set(KeyName, Result.c_str());
  }

  return RespBuilder.createResponse();
}

static std::string mangleSimpleClass(StringRef moduleName,
                                     StringRef className) {
  using namespace swift::Demangle;
  Demangler Dem;
  auto moduleNode = Dem.createNode(Node::Kind::Module, moduleName);
  auto IdNode = Dem.createNode(Node::Kind::Identifier, className);
  auto classNode = Dem.createNode(Node::Kind::Class);
  auto typeNode = Dem.createNode(Node::Kind::Type);
  auto typeManglingNode = Dem.createNode(Node::Kind::TypeMangling);
  auto globalNode = Dem.createNode(Node::Kind::Global);

  classNode->addChild(moduleNode, Dem);
  classNode->addChild(IdNode, Dem);
  typeNode->addChild(classNode, Dem);
  typeManglingNode->addChild(typeNode, Dem);
  globalNode->addChild(typeManglingNode, Dem);
  return mangleNode(globalNode);
}

static sourcekitd_response_t
mangleSimpleClassNames(ArrayRef<std::pair<StringRef, StringRef>> ModuleClassPairs) {
  ResponseBuilder RespBuilder;
  auto Arr = RespBuilder.getDictionary().setArray(KeyResults);
  for (auto &pair : ModuleClassPairs) {
    std::string Result = mangleSimpleClass(pair.first, pair.second);
    auto Entry = Arr.appendDictionary();
    Entry.set(KeyName, Result.c_str());
  }

  return RespBuilder.createResponse();
}

static sourcekitd_response_t reportDocInfo(llvm::MemoryBuffer *InputBuf,
                                           StringRef ModuleName,
                                           ArrayRef<const char *> Args) {
  ResponseBuilder RespBuilder;
  SKDocConsumer DocConsumer(RespBuilder);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.getDocInfo(InputBuf, ModuleName, Args, DocConsumer);

  if (!DocConsumer.ErrorDescription.empty())
    return createErrorRequestFailed(DocConsumer.ErrorDescription.c_str());

  return DocConsumer.createResponse();
}

void SKDocConsumer::addDocEntityInfoToDict(const DocEntityInfo &Info,
                                           ResponseBuilder::Dictionary Elem) {
  Elem.set(KeyKind, Info.Kind);
  if (!Info.Name.empty())
    Elem.set(KeyName, Info.Name);
  if (!Info.Argument.empty())
    Elem.set(KeyKeyword, Info.Argument);
  if (!Info.SubModuleName.empty())
    Elem.set(KeyModuleName, Info.SubModuleName);
  if (!Info.USR.empty())
    Elem.set(KeyUSR, Info.USR);
  if (!Info.OriginalUSR.empty())
    Elem.set(KeyOriginalUSR, Info.OriginalUSR);
  if (!Info.ProvideImplementationOfUSR.empty())
    Elem.set(KeyDefaultImplementationOf, Info.ProvideImplementationOfUSR);
  if (Info.Length > 0) {
    Elem.set(KeyOffset, Info.Offset);
    Elem.set(KeyLength, Info.Length);
  }
  if (Info.IsUnavailable)
    Elem.set(KeyIsUnavailable, Info.IsUnavailable);
  if (Info.IsDeprecated)
    Elem.set(KeyIsDeprecated, Info.IsDeprecated);
  if (Info.IsOptional)
    Elem.set(KeyIsOptional, Info.IsOptional);
  if (!Info.DocComment.empty())
    Elem.set(KeyDocFullAsXML, Info.DocComment);
  if (!Info.FullyAnnotatedDecl.empty())
    Elem.set(KeyFullyAnnotatedDecl, Info.FullyAnnotatedDecl);
  if (!Info.LocalizationKey.empty())
    Elem.set(KeyLocalizationKey, Info.LocalizationKey);

  if (!Info.GenericParams.empty()) {
    auto GPArray = Elem.setArray(KeyGenericParams);
    for (auto &GP : Info.GenericParams) {
      auto GPElem = GPArray.appendDictionary();
      GPElem.set(KeyName, GP.Name);
      if (!GP.Inherits.empty())
        GPElem.set(KeyInherits, GP.Inherits);
    }
  }
  // Note that due to protocol extensions, GenericRequirements may be non-empty
  // while GenericParams is empty.
  if (!Info.GenericRequirements.empty()) {
    auto ReqArray = Elem.setArray(KeyGenericRequirements);
    for (auto &Req : Info.GenericRequirements) {
      auto ReqElem = ReqArray.appendDictionary();
      ReqElem.set(KeyDescription, Req);
    }
  }
}

void SKDocConsumer::failed(StringRef ErrDescription) {
  ErrorDescription = ErrDescription;
}

bool SKDocConsumer::handleSourceText(StringRef Text) {
  TopDict.set(KeySourceText, Text);
  return true;
}

bool SKDocConsumer::handleAnnotation(const DocEntityInfo &Info) {
  AnnotationsBuilder.add(Info);
  return true;
}

bool SKDocConsumer::startSourceEntity(const DocEntityInfo &Info) {
  Entity &Parent = EntitiesStack.back();
  ResponseBuilder::Array &Arr = Parent.Entities;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyEntities);

  auto Elem = Arr.appendDictionary();
  addDocEntityInfoToDict(Info, Elem);

  EntitiesStack.push_back({ Info.Kind, Elem, ResponseBuilder::Array(),
                            ResponseBuilder::Array(),
                            ResponseBuilder::Array(),
                            ResponseBuilder::Array()});
  return true;
}

bool SKDocConsumer::handleInheritsEntity(const DocEntityInfo &Info) {
  assert(EntitiesStack.size() > 1 && "Related entity at top-level ?");
  Entity &Parent = EntitiesStack.back();
  ResponseBuilder::Array &Arr = Parent.Inherits;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyInherits);

  addDocEntityInfoToDict(Info, Arr.appendDictionary());
  return true;
}

bool SKDocConsumer::handleConformsToEntity(const DocEntityInfo &Info) {
  assert(EntitiesStack.size() > 1 && "Related entity at top-level ?");
  Entity &Parent = EntitiesStack.back();
  ResponseBuilder::Array &Arr = Parent.Conforms;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyConforms);

  addDocEntityInfoToDict(Info, Arr.appendDictionary());
  return true;
}

bool SKDocConsumer::handleExtendsEntity(const DocEntityInfo &Info) {
  assert(EntitiesStack.size() > 1 && "Related entity at top-level ?");
  Entity &Parent = EntitiesStack.back();
  addDocEntityInfoToDict(Info, Parent.Data.setDictionary(KeyExtends));
  return true;
}

bool SKDocConsumer::handleAvailableAttribute(const AvailableAttrInfo &Info) {
  Entity &Parent = EntitiesStack.back();
  ResponseBuilder::Array &Arr = Parent.Attrs;
  if (Arr.isNull())
    Arr = Parent.Data.setArray(KeyAttributes);

  auto Elem = Arr.appendDictionary();
  Elem.set(KeyKind, Info.AttrKind);
  if (Info.IsUnavailable)
    Elem.set(KeyIsUnavailable, Info.IsUnavailable);
  if (Info.IsDeprecated)
    Elem.set(KeyIsDeprecated, Info.IsDeprecated);
  if (Info.Platform.isValid())
    Elem.set(KeyPlatform, Info.Platform);
  if (!Info.Message.empty())
    Elem.set(KeyMessage, Info.Message);
  if (Info.Introduced.hasValue())
    Elem.set(KeyIntroduced, Info.Introduced.getValue().getAsString());
  if (Info.Deprecated.hasValue())
    Elem.set(KeyDeprecated, Info.Deprecated.getValue().getAsString());
  if (Info.Obsoleted.hasValue())
    Elem.set(KeyObsoleted, Info.Obsoleted.getValue().getAsString());

  return true;
}

bool SKDocConsumer::finishSourceEntity(UIdent Kind) {
  Entity &CurrEnt = EntitiesStack.back();
  assert(CurrEnt.Kind == Kind);
  (void) CurrEnt;
  EntitiesStack.pop_back();
  return true;
}

bool SKDocConsumer::handleDiagnostic(const DiagnosticEntryInfo &Info) {
  ResponseBuilder::Array &Arr = Diags;
  if (Arr.isNull())
    Arr = TopDict.setArray(KeyDiagnostics);

  auto Elem = Arr.appendDictionary();
  UIdent SeverityUID;
  switch (Info.Severity) {
  case DiagnosticSeverityKind::Warning:
    SeverityUID = UIdent(KindDiagWarning.str());
    break;
  case DiagnosticSeverityKind::Error:
    SeverityUID = UIdent(KindDiagError.str());
    break;
  }

  Elem.set(KeySeverity, SeverityUID);
  fillDictionaryForDiagnosticInfo(Elem, Info);

  if (!Info.Notes.empty()) {
    auto NotesArr = Elem.setArray(KeyDiagnostics);
    for (auto &NoteDiag : Info.Notes) {
      auto NoteElem = NotesArr.appendDictionary();
      NoteElem.set(KeySeverity, KindDiagNote);
      fillDictionaryForDiagnosticInfo(NoteElem, NoteDiag);
    }
  }

  return true;
}

//===----------------------------------------------------------------------===//
// ReportCursorInfo
//===----------------------------------------------------------------------===//

static void reportCursorInfo(const CursorInfo &Info, ResponseReceiver Rec) {

  if (Info.IsCancelled)
    return Rec(createErrorRequestCancelled());

  ResponseBuilder RespBuilder;
  if (Info.Kind.isInvalid())
    return Rec(RespBuilder.createResponse());

  auto Elem = RespBuilder.getDictionary();
  Elem.set(KeyKind, Info.Kind);
  Elem.set(KeyName, Info.Name);
  if (!Info.USR.empty())
    Elem.set(KeyUSR, Info.USR);
  if (!Info.TypeName.empty())
    Elem.set(KeyTypeName, Info.TypeName);
  if (!Info.DocComment.empty())
    Elem.set(KeyDocFullAsXML, Info.DocComment);
  if (!Info.AnnotatedDeclaration.empty())
    Elem.set(KeyAnnotatedDecl, Info.AnnotatedDeclaration);
  if (!Info.FullyAnnotatedDeclaration.empty())
    Elem.set(KeyFullyAnnotatedDecl, Info.FullyAnnotatedDeclaration);
  if (!Info.ModuleName.empty())
    Elem.set(KeyModuleName, Info.ModuleName);
  if (!Info.GroupName.empty())
    Elem.set(KeyGroupName, Info.GroupName);
  if (!Info.LocalizationKey.empty())
    Elem.set(KeyLocalizationKey, Info.LocalizationKey);
  if (!Info.ModuleInterfaceName.empty())
    Elem.set(KeyModuleInterfaceName, Info.ModuleInterfaceName);
  if (Info.DeclarationLoc.hasValue()) {
    Elem.set(KeyOffset, Info.DeclarationLoc.getValue().first);
    Elem.set(KeyLength, Info.DeclarationLoc.getValue().second);
    if (!Info.Filename.empty())
      Elem.set(KeyFilePath, Info.Filename);
  }
  if (!Info.OverrideUSRs.empty()) {
    auto Overrides = Elem.setArray(KeyOverrides);
    for (auto USR : Info.OverrideUSRs) {
      auto Override = Overrides.appendDictionary();
      Override.set(KeyUSR, USR);
    }
  }
  if (!Info.ModuleGroupArray.empty()) {
    auto Groups = Elem.setArray(KeyModuleGroups);
    for (auto Name : Info.ModuleGroupArray) {
      auto Entry = Groups.appendDictionary();
      Entry.set(KeyGroupName, Name);
    }
  }
  if (!Info.AvailableActions.empty()) {
    auto Actions = Elem.setArray(KeyActionable);
    for (auto Name : Info.AvailableActions) {
      auto Entry = Actions.appendDictionary();
      Entry.set(KeyActionName, Name);
    }
  }
  if (Info.ParentNameOffset) {
    Elem.set(KeyParentLoc, Info.ParentNameOffset.getValue());
  }
  if (!Info.AnnotatedRelatedDeclarations.empty()) {
    auto RelDecls = Elem.setArray(KeyRelatedDecls);
    for (auto AnnotDecl : Info.AnnotatedRelatedDeclarations) {
      auto RelDecl = RelDecls.appendDictionary();
      RelDecl.set(KeyAnnotatedDecl, AnnotDecl);
    }
  }
  if (Info.IsSystem)
    Elem.setBool(KeyIsSystem, true);
  if (!Info.TypeInterface.empty())
    Elem.set(KeyTypeInterface, Info.TypeInterface);
  if (!Info.TypeUSR.empty())
    Elem.set(KeyTypeUsr, Info.TypeUSR);
  if (!Info.ContainerTypeUSR.empty())
    Elem.set(KeyContainerTypeUsr, Info.ContainerTypeUSR);

  return Rec(RespBuilder.createResponse());
}

//===----------------------------------------------------------------------===//
// ReportRangeInfo
//===----------------------------------------------------------------------===//

static void reportRangeInfo(const RangeInfo &Info, ResponseReceiver Rec) {
  if (Info.IsCancelled)
    return Rec(createErrorRequestCancelled());
  ResponseBuilder RespBuilder;
  auto Elem = RespBuilder.getDictionary();
  Elem.set(KeyKind, Info.RangeKind);
  Elem.set(KeyTypeName, Info.ExprType);
  Elem.set(KeyRangeContent, Info.RangeContent);
  Rec(RespBuilder.createResponse());
}

//===----------------------------------------------------------------------===//
// ReportNameInfo
//===----------------------------------------------------------------------===//

static void reportNameInfo(const NameTranslatingInfo &Info, ResponseReceiver Rec) {
  if (Info.IsCancelled)
    return Rec(createErrorRequestCancelled());

  ResponseBuilder RespBuilder;
  if (Info.NameKind.isInvalid())
    return Rec(RespBuilder.createResponse());
  if (Info.BaseName.empty() && Info.ArgNames.empty())
    return Rec(RespBuilder.createResponse());

  auto Elem = RespBuilder.getDictionary();
  Elem.set(KeyNameKind, Info.NameKind);

  if (!Info.BaseName.empty()) {
    Elem.set(KeyBaseName, Info.BaseName);
  }
  if (!Info.ArgNames.empty()) {
    auto Arr = Elem.setArray(Info.NameKind == UIdent(KindNameSwift.str()) ?
                               KeyArgNames : KeySelectorPieces);
    for (auto N : Info.ArgNames) {
      auto NameEle = Arr.appendDictionary();
      NameEle.set(KeyName, N);
    }
  }
  if (Info.IsZeroArgSelector) {
    Elem.set(KeyIsZeroArgSelector, Info.IsZeroArgSelector);
  }
  Rec(RespBuilder.createResponse());
}

//===----------------------------------------------------------------------===//
// FindRelatedIdents
//===----------------------------------------------------------------------===//

static void findRelatedIdents(StringRef Filename,
                              int64_t Offset,
                              bool CancelOnSubsequentRequest,
                              ArrayRef<const char *> Args,
                              ResponseReceiver Rec) {
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.findRelatedIdentifiersInFile(Filename, Offset, CancelOnSubsequentRequest,
                                    Args, [Rec](const RelatedIdentsInfo &Info) {
    if (Info.IsCancelled)
      return Rec(createErrorRequestCancelled());

    ResponseBuilder RespBuilder;
    auto Arr = RespBuilder.getDictionary().setArray(KeyResults);
    for (auto R : Info.Ranges) {
      auto Elem = Arr.appendDictionary();
      Elem.set(KeyOffset, R.first);
      Elem.set(KeyLength, R.second);
    }

    Rec(RespBuilder.createResponse());
  });
}

//===----------------------------------------------------------------------===//
// CodeComplete
//===----------------------------------------------------------------------===//

namespace {
class SKCodeCompletionConsumer : public CodeCompletionConsumer {
  ResponseBuilder &RespBuilder;
  CodeCompletionResultsArrayBuilder ResultsBuilder;

  std::string ErrorDescription;

public:
  explicit SKCodeCompletionConsumer(ResponseBuilder &RespBuilder)
    : RespBuilder(RespBuilder) {
  }

  sourcekitd_response_t createResponse() {
    if (!ErrorDescription.empty())
      return createErrorRequestFailed(ErrorDescription.c_str());

    RespBuilder.getDictionary().setCustomBuffer(KeyResults,
        CustomBufferKind::CodeCompletionResultsArray,
        ResultsBuilder.createBuffer());
    return RespBuilder.createResponse();
  }


  void failed(StringRef ErrDescription) override;

  bool handleResult(const CodeCompletionInfo &Info) override;
};
} // end anonymous namespace

static sourcekitd_response_t codeComplete(llvm::MemoryBuffer *InputBuf,
                                          int64_t Offset,
                                          ArrayRef<const char *> Args) {
  ResponseBuilder RespBuilder;
  SKCodeCompletionConsumer CCC(RespBuilder);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.codeComplete(InputBuf, Offset, CCC, Args);
  return CCC.createResponse();
}

void SKCodeCompletionConsumer::failed(StringRef ErrDescription) {
  ErrorDescription = ErrDescription;
}

bool SKCodeCompletionConsumer::handleResult(const CodeCompletionInfo &R) {
  Optional<StringRef> ModuleNameOpt;
  if (!R.ModuleName.empty())
    ModuleNameOpt = R.ModuleName;
  Optional<StringRef> DocBriefOpt;
  if (!R.DocBrief.empty())
    DocBriefOpt = R.DocBrief;
  Optional<StringRef> AssocUSRsOpt;
  if (!R.AssocUSRs.empty())
    AssocUSRsOpt = R.AssocUSRs;

  assert(!R.ModuleImportDepth && "not implemented on CompactArray path");

  ResultsBuilder.add(R.Kind,
                     R.Name,
                     R.Description,
                     R.SourceText,
                     R.TypeName,
                     ModuleNameOpt,
                     DocBriefOpt,
                     AssocUSRsOpt,
                     R.SemanticContext,
                     R.NotRecommended,
                     R.NumBytesToErase);
  return true;
}


//===----------------------------------------------------------------------===//
// (New) CodeComplete
//===----------------------------------------------------------------------===//

namespace {
class SKGroupedCodeCompletionConsumer : public GroupedCodeCompletionConsumer {
  ResponseBuilder &RespBuilder;
  ResponseBuilder::Dictionary Response;
  SmallVector<ResponseBuilder::Array, 3> GroupContentsStack;
  std::string ErrorDescription;

public:
  explicit SKGroupedCodeCompletionConsumer(ResponseBuilder &RespBuilder)
      : RespBuilder(RespBuilder) {}

  sourcekitd_response_t createResponse() {
    if (!ErrorDescription.empty())
      return createErrorRequestFailed(ErrorDescription.c_str());
    assert(GroupContentsStack.empty() && "mismatched start/endGroup");
    return RespBuilder.createResponse();
  }

  void failed(StringRef ErrDescription) override;
  bool handleResult(const CodeCompletionInfo &Info) override;
  void startGroup(UIdent kind, StringRef name) override;
  void endGroup() override;
  void setNextRequestStart(unsigned offset) override;
};

class SKOptionsDictionary : public OptionsDictionary {
  RequestDict &Options;

public:
  explicit SKOptionsDictionary(RequestDict &Options) : Options(Options) {}

  bool valueForOption(UIdent Key, unsigned &Val) override {
    int64_t result;
    if (Options.getInt64(Key, result, false))
      return false;
    Val = static_cast<unsigned>(result);
    return true;
  }

  bool valueForOption(UIdent Key, bool &Val) override {
    int64_t result;
    if (Options.getInt64(Key, result, false))
      return false;
    Val = result ? true : false;
    return true;
  }

  bool valueForOption(UIdent Key, StringRef &Val) override {
    Optional<StringRef> value = Options.getString(Key);
    if (!value)
      return false;
    Val = *value;
    return true;
  }
};
} // end anonymous namespace

static sourcekitd_response_t codeCompleteOpen(StringRef Name,
                                              llvm::MemoryBuffer *InputBuf,
                                              int64_t Offset,
                                              Optional<RequestDict> optionsDict,
                                              ArrayRef<const char *> Args) {
  ResponseBuilder RespBuilder;
  SKGroupedCodeCompletionConsumer CCC(RespBuilder);
  std::unique_ptr<SKOptionsDictionary> options;
  std::vector<FilterRule> filterRules;
  if (optionsDict) {
    options = llvm::make_unique<SKOptionsDictionary>(*optionsDict);
    bool failed = false;
    optionsDict->dictionaryArrayApply(KeyFilterRules, [&](RequestDict dict) {
      FilterRule rule;
      auto kind = dict.getUID(KeyKind);
      if (kind == KindCodeCompletionEverything) {
        rule.kind = FilterRule::Everything;
      } else if (kind == KindCodeCompletionModule) {
        rule.kind = FilterRule::Module;
      } else if (kind == KindCodeCompletionKeyword) {
        rule.kind = FilterRule::Keyword;
      } else if (kind == KindCodeCompletionLiteral) {
        rule.kind = FilterRule::Literal;
      } else if (kind == KindCodeCompletionCustom) {
        rule.kind = FilterRule::CustomCompletion;
      } else if (kind == KindCodeCompletionIdentifier) {
        rule.kind = FilterRule::Identifier;
      } else if (kind == KindCodeCompletionDescription) {
        rule.kind = FilterRule::Description;
      } else {
        // Warning: unknown
      }

      int64_t hide;
      if (dict.getInt64(KeyHide, hide, false)) {
        failed = true;
        CCC.failed("filter rule missing required key 'key.hide'");
        return true;
      }

      rule.hide = hide;

      switch (rule.kind) {
      case FilterRule::Everything:
        break;
      case FilterRule::Module:
      case FilterRule::Identifier: {
        SmallVector<const char *, 8> names;
        if (dict.getStringArray(KeyNames, names, false)) {
          failed = true;
          CCC.failed("filter rule missing required key 'key.names'");
          return true;
        }
        rule.names.assign(names.begin(), names.end());
        break;
      }
      case FilterRule::Description: {
        SmallVector<const char *, 8> names;
        if (dict.getStringArray(KeyNames, names, false)) {
          failed = true;
          CCC.failed("filter rule missing required key 'key.names'");
          return true;
        }
        rule.names.assign(names.begin(), names.end());
        break;
      }
      case FilterRule::Keyword:
      case FilterRule::Literal:
      case FilterRule::CustomCompletion: {
        SmallVector<sourcekitd_uid_t, 8> uids;
        dict.getUIDArray(KeyUIDs, uids, true);
        for (auto uid : uids)
          rule.uids.push_back(UIdentFromSKDUID(uid));
        break;
      }
      }

      filterRules.push_back(std::move(rule));
      return false; // continue
    });

    if (failed)
      return CCC.createResponse();
  }
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.codeCompleteOpen(Name, InputBuf, Offset, options.get(), filterRules, CCC,
                        Args);
  return CCC.createResponse();
}

static sourcekitd_response_t codeCompleteClose(StringRef Name, int64_t Offset) {
  ResponseBuilder RespBuilder;
  SKGroupedCodeCompletionConsumer CCC(RespBuilder);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.codeCompleteClose(Name, Offset, CCC);
  return CCC.createResponse();
}

static sourcekitd_response_t
codeCompleteUpdate(StringRef name, int64_t offset,
                   Optional<RequestDict> optionsDict) {
  ResponseBuilder RespBuilder;
  SKGroupedCodeCompletionConsumer CCC(RespBuilder);
  std::unique_ptr<SKOptionsDictionary> options;
  if (optionsDict)
    options = llvm::make_unique<SKOptionsDictionary>(*optionsDict);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.codeCompleteUpdate(name, offset, options.get(), CCC);
  return CCC.createResponse();
}

void SKGroupedCodeCompletionConsumer::failed(StringRef ErrDescription) {
  ErrorDescription = ErrDescription;
}

bool SKGroupedCodeCompletionConsumer::handleResult(const CodeCompletionInfo &R) {
  assert(!GroupContentsStack.empty() && "missing root group");

  auto result = GroupContentsStack.back().appendDictionary();
  if (R.CustomKind)
    result.set(KeyKind, sourcekitd_uid_t(R.CustomKind));
  else
    result.set(KeyKind, R.Kind);
  result.set(KeyName, R.Name);
  result.set(KeyDescription, R.Description);
  result.set(KeySourceText, R.SourceText);
  result.set(KeyTypeName, R.TypeName);
  result.set(KeyContext, R.SemanticContext);
  if (!R.ModuleName.empty())
    result.set(KeyModuleName, R.ModuleName);
  if (!R.DocBrief.empty())
    result.set(KeyDocBrief, R.DocBrief);
  if (!R.AssocUSRs.empty())
    result.set(KeyAssociatedUSRs, R.AssocUSRs);
  if (R.ModuleImportDepth)
    result.set(KeyModuleImportDepth, *R.ModuleImportDepth);
  if (R.NotRecommended)
    result.set(KeyNotRecommended, R.NotRecommended);
  result.set(KeyNumBytesToErase, R.NumBytesToErase);

  if (R.descriptionStructure) {
    auto addRange = [](ResponseBuilder::Dictionary dict, UIdent offset,
                       UIdent length, CodeCompletionInfo::IndexRange range) {
      if (!range.empty()) {
        dict.set(offset, range.begin);
        dict.set(length, range.length());
      }
    };

    auto structure = result.setDictionary(KeySubStructure);
    addRange(structure, KeyNameOffset, KeyNameLength,
             R.descriptionStructure->baseName);
    addRange(structure, KeyBodyOffset, KeyBodyLength,
             R.descriptionStructure->parameterRange);
    addRange(structure, KeyThrowOffset, KeyThrowLength,
             R.descriptionStructure->throwsRange);

    if (R.parametersStructure) {
      auto params = structure.setArray(KeySubStructure);
      for (auto &P : *R.parametersStructure) {
        auto param = params.appendDictionary();
        addRange(param, KeyNameOffset, KeyNameLength, P.name);
        addRange(param, KeyBodyOffset, KeyBodyLength, P.afterColon);
        if (P.isLocalName)
          param.set(KeyIsLocal, true);
      }
    }
  }

  return true;
}

void SKGroupedCodeCompletionConsumer::startGroup(UIdent kind, StringRef name) {
  ResponseBuilder::Dictionary group;
  if (GroupContentsStack.empty()) {
    group = RespBuilder.getDictionary();
    Response = group;
  } else {
    group = GroupContentsStack.back().appendDictionary();
  }
  group.set(KeyKind, kind);
  group.set(KeyName, name);
  auto contents = group.setArray(KeyResults);
  GroupContentsStack.push_back(contents);
}
void SKGroupedCodeCompletionConsumer::endGroup() {
  assert(!GroupContentsStack.empty());
  GroupContentsStack.pop_back();
}
void SKGroupedCodeCompletionConsumer::setNextRequestStart(unsigned offset) {
  assert(!Response.isNull());
  Response.set(KeyNextRequestStart, offset);
}

//===----------------------------------------------------------------------===//
// Editor
//===----------------------------------------------------------------------===//

namespace {
class SKEditorConsumer : public EditorConsumer {
  ResponseReceiver RespReceiver;
  ResponseBuilder RespBuilder;

  ResponseBuilder::Dictionary Dict;
  DocStructureArrayBuilder DocStructure;
  TokenAnnotationsArrayBuilder SyntaxMap;
  TokenAnnotationsArrayBuilder SemanticAnnotations;

  ResponseBuilder::Array Diags;
  sourcekitd_response_t Error = nullptr;

  bool EnableSyntaxMap;
  bool EnableStructure;
  bool EnableDiagnostics;
  bool SyntacticOnly;

public:
  SKEditorConsumer(bool EnableSyntaxMap, bool EnableStructure,
                   bool EnableDiagnostics, bool SyntacticOnly)
      : EnableSyntaxMap(EnableSyntaxMap), EnableStructure(EnableStructure),
        EnableDiagnostics(EnableDiagnostics), SyntacticOnly(SyntacticOnly) {

    Dict = RespBuilder.getDictionary();
  }

  SKEditorConsumer(ResponseReceiver RespReceiver, bool EnableSyntaxMap,
                   bool EnableStructure, bool EnableDiagnostics,
                   bool SyntacticOnly)
  : SKEditorConsumer(EnableSyntaxMap, EnableStructure,
                     EnableDiagnostics, SyntacticOnly) {
    this->RespReceiver = RespReceiver;
  }

  sourcekitd_response_t createResponse();

  bool needsSemanticInfo() override {
    return !SyntacticOnly && !isSemanticEditorDisabled();
  }

  void handleRequestError(const char *Description) override;

  bool handleSyntaxMap(unsigned Offset, unsigned Length, UIdent Kind) override;

  bool handleSemanticAnnotation(unsigned Offset, unsigned Length, UIdent Kind,
                                bool isSystem) override;

  bool beginDocumentSubStructure(unsigned Offset, unsigned Length, UIdent Kind,
                                 UIdent AccessLevel,
                                 UIdent SetterAccessLevel,
                                 unsigned NameOffset,
                                 unsigned NameLength,
                                 unsigned BodyOffset,
                                 unsigned BodyLength,
                                 StringRef DisplayName,
                                 StringRef TypeName,
                                 StringRef RuntimeName,
                                 StringRef SelectorName,
                                 ArrayRef<StringRef> InheritedTypes,
                                 ArrayRef<UIdent> Attrs) override;

  bool endDocumentSubStructure() override;

  bool handleDocumentSubStructureElement(UIdent Kind,
                                         unsigned Offset,
                                         unsigned Length) override;

  bool recordAffectedRange(unsigned Offset, unsigned Length) override;

  bool recordAffectedLineRange(unsigned Line, unsigned Length) override;

  bool recordFormattedText(StringRef Text) override;

  bool setDiagnosticStage(UIdent DiagStage) override;
  bool handleDiagnostic(const DiagnosticEntryInfo &Info,
                        UIdent DiagStage) override;

  bool handleSourceText(StringRef Text) override;

  void finished() override {
    if (RespReceiver)
      RespReceiver(createResponse());
  }
};

} // end anonymous namespace

static sourcekitd_response_t
editorOpen(StringRef Name, llvm::MemoryBuffer *Buf, bool EnableSyntaxMap,
           bool EnableStructure, bool EnableDiagnostics, bool SyntacticOnly,
           ArrayRef<const char *> Args) {
  SKEditorConsumer EditC(EnableSyntaxMap, EnableStructure,
                         EnableDiagnostics, SyntacticOnly);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorOpen(Name, Buf, EnableSyntaxMap, EditC, Args);
  return EditC.createResponse();
}

static sourcekitd_response_t
editorOpenInterface(StringRef Name, StringRef ModuleName,
                    Optional<StringRef> Group, ArrayRef<const char *> Args,
                    bool SynthesizedExtensions,
                    Optional<StringRef> InterestedUSR) {
  SKEditorConsumer EditC(/*EnableSyntaxMap=*/true,
                         /*EnableStructure=*/true,
                         /*EnableDiagnostics=*/false,
                         /*SyntacticOnly=*/false);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorOpenInterface(EditC, Name, ModuleName, Group, Args,
                           SynthesizedExtensions, InterestedUSR);
  return EditC.createResponse();
}


/// Getting the interface from a swift source file differs from getting interfaces
/// from headers or modules for its performing asynchronously.
static void
editorOpenSwiftSourceInterface(StringRef Name, StringRef HeaderName,
                               ArrayRef<const char *> Args,
                               ResponseReceiver Rec) {
  auto EditC = std::make_shared<SKEditorConsumer>(Rec,
                                                  /*EnableSyntaxMap=*/true,
                                                  /*EnableStructure=*/true,
                                                  /*EnableDiagnostics=*/false,
                                                  /*SyntacticOnly=*/false);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorOpenSwiftSourceInterface(Name, HeaderName, Args, EditC);
}

static void
editorOpenSwiftTypeInterface(StringRef TypeUsr, ArrayRef<const char *> Args,
                             ResponseReceiver Rec) {
  auto EditC = std::make_shared<SKEditorConsumer>(Rec,
                                                  /*EnableSyntaxMap=*/true,
                                                  /*EnableStructure=*/true,
                                                  /*EnableDiagnostics=*/false,
                                                  /*SyntacticOnly=*/false);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorOpenTypeInterface(*EditC, Args, TypeUsr);
}

static sourcekitd_response_t editorExtractTextFromComment(StringRef Source) {
  SKEditorConsumer EditC(/*EnableSyntaxMap=*/false,
                         /*EnableStructure=*/false,
                         /*EnableDiagnostics=*/false,
                         /*SyntacticOnly=*/true);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorExtractTextFromComment(Source, EditC);
  return EditC.createResponse();
}

static sourcekitd_response_t editorConvertMarkupToXML(StringRef Source) {
  SKEditorConsumer EditC(/*EnableSyntaxMap=*/false,
                         /*EnableStructure=*/false,
                         /*EnableDiagnostics=*/false,
                         /*SyntacticOnly=*/true);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorConvertMarkupToXML(Source, EditC);
  return EditC.createResponse();
}

static sourcekitd_response_t
editorOpenHeaderInterface(StringRef Name, StringRef HeaderName,
                          ArrayRef<const char *> Args,
                          bool UsingSwiftArgs,
                          bool SynthesizedExtensions,
                          Optional<unsigned> swiftVersion) {
  SKEditorConsumer EditC(/*EnableSyntaxMap=*/true,
                         /*EnableStructure=*/true,
                         /*EnableDiagnostics=*/false,
                         /*SyntacticOnly=*/false);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorOpenHeaderInterface(EditC, Name, HeaderName, Args, UsingSwiftArgs,
                                 SynthesizedExtensions, swiftVersion);
  return EditC.createResponse();
}

static sourcekitd_response_t
editorClose(StringRef Name, bool RemoveCache) {
  ResponseBuilder RespBuilder;
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorClose(Name, RemoveCache);
  return RespBuilder.createResponse();
}

static sourcekitd_response_t
editorReplaceText(StringRef Name, llvm::MemoryBuffer *Buf, unsigned Offset,
                  unsigned Length, bool EnableSyntaxMap, bool EnableStructure,
                  bool EnableDiagnostics, bool SyntacticOnly) {
  SKEditorConsumer EditC(EnableSyntaxMap, EnableStructure,
                         EnableDiagnostics, SyntacticOnly);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorReplaceText(Name, Buf, Offset, Length, EditC);
  return EditC.createResponse();
}

static void
editorApplyFormatOptions(StringRef Name, RequestDict &FmtOptions) {
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  SKOptionsDictionary SKFmtOptions(FmtOptions);
  Lang.editorApplyFormatOptions(Name, SKFmtOptions);
}

static sourcekitd_response_t
editorFormatText(StringRef Name, unsigned Line, unsigned Length) {
  SKEditorConsumer EditC(false, false, false,
                         /*SyntacticOnly=*/true);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorFormatText(Name, Line, Length, EditC);
  return EditC.createResponse();
}

static sourcekitd_response_t
editorExpandPlaceholder(StringRef Name, unsigned Offset, unsigned Length) {
  SKEditorConsumer EditC(false, false, false,
                         /*SyntacticOnly=*/true);
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.editorExpandPlaceholder(Name, Offset, Length, EditC);
  return EditC.createResponse();
}

sourcekitd_response_t SKEditorConsumer::createResponse() {
  if (Error)
    return Error;

  if (EnableSyntaxMap) {
    Dict.setCustomBuffer(KeySyntaxMap,
        CustomBufferKind::TokenAnnotationsArray,
        SyntaxMap.createBuffer());
  }
  if (!SemanticAnnotations.empty()) {
    Dict.setCustomBuffer(KeyAnnotations,
        CustomBufferKind::TokenAnnotationsArray,
        SemanticAnnotations.createBuffer());
  }
  if (EnableStructure) {
    Dict.setCustomBuffer(KeySubStructure, CustomBufferKind::DocStructureArray,
                         DocStructure.createBuffer());
  }

  return RespBuilder.createResponse();
}

void SKEditorConsumer::handleRequestError(const char *Description) {
  if (!Error) {
    Error = createErrorRequestFailed(Description);
  }
  if (RespReceiver) {
    RespReceiver(Error);
    RespReceiver = ResponseReceiver();
  }
}

bool SKEditorConsumer::handleSyntaxMap(unsigned Offset, unsigned Length,
                                       UIdent Kind) {
  if (!EnableSyntaxMap)
    return true;

  SyntaxMap.add(Kind, Offset, Length, /*IsSystem=*/false);
  return true;
}

bool SKEditorConsumer::handleSemanticAnnotation(unsigned Offset,
                                                unsigned Length,
                                                UIdent Kind, bool isSystem) {
  assert(Kind.isValid());
  SemanticAnnotations.add(Kind, Offset, Length, isSystem);
  return true;
}

bool
SKEditorConsumer::beginDocumentSubStructure(unsigned Offset,
                                            unsigned Length, UIdent Kind,
                                            UIdent AccessLevel,
                                            UIdent SetterAccessLevel,
                                            unsigned NameOffset,
                                            unsigned NameLength,
                                            unsigned BodyOffset,
                                            unsigned BodyLength,
                                            StringRef DisplayName,
                                            StringRef TypeName,
                                            StringRef RuntimeName,
                                            StringRef SelectorName,
                                            ArrayRef<StringRef> InheritedTypes,
                                            ArrayRef<UIdent> Attrs) {
  if (EnableStructure) {
    DocStructure.beginSubStructure(
        Offset, Length, Kind, AccessLevel, SetterAccessLevel, NameOffset,
        NameLength, BodyOffset, BodyLength, DisplayName, TypeName, RuntimeName,
        SelectorName, InheritedTypes, Attrs);
  }
  return true;
}

bool SKEditorConsumer::endDocumentSubStructure() {
  if (EnableStructure)
    DocStructure.endSubStructure();
  return true;
}

bool SKEditorConsumer::handleDocumentSubStructureElement(UIdent Kind,
                                                         unsigned Offset,
                                                         unsigned Length) {
  if (EnableStructure)
    DocStructure.addElement(Kind, Offset, Length);
  return true;
}

bool SKEditorConsumer::recordAffectedRange(unsigned Offset, unsigned Length) {
  Dict.set(KeyOffset, Offset);
  Dict.set(KeyLength, Length);

  return true;
}

bool SKEditorConsumer::recordAffectedLineRange(unsigned Line, unsigned Length) {
  Dict.set(KeyLine, Line);
  Dict.set(KeyLength, Length);

  return true;
}

bool SKEditorConsumer::recordFormattedText(StringRef Text) {
  Dict.set(KeySourceText, Text);

  return true;
}

static void fillDictionaryForDiagnosticInfo(
    ResponseBuilder::Dictionary Elem, const DiagnosticEntryInfoBase &Info) {

  Elem.set(KeyDescription, Info.Description);
  if (Info.Line != 0) {
    Elem.set(KeyLine, Info.Line);
    Elem.set(KeyColumn, Info.Column);
  } else {
    Elem.set(KeyOffset, Info.Offset);
  }
  if (!Info.Filename.empty())
    Elem.set(KeyFilePath, Info.Filename);

  if (!Info.Ranges.empty()) {
    auto RangesArr = Elem.setArray(KeyRanges);
    for (auto R : Info.Ranges) {
      auto RangeElem = RangesArr.appendDictionary();
      RangeElem.set(KeyOffset, R.first);
      RangeElem.set(KeyLength, R.second);
    }
  }

  if (!Info.Fixits.empty()) {
    auto FixitsArr = Elem.setArray(KeyFixits);
    for (auto F : Info.Fixits) {
      auto FixitElem = FixitsArr.appendDictionary();
      FixitElem.set(KeyOffset, F.Offset);
      FixitElem.set(KeyLength, F.Length);
      FixitElem.set(KeySourceText, F.Text);
    }
  }
}

bool SKEditorConsumer::setDiagnosticStage(UIdent DiagStage) {
  Dict.set(KeyDiagnosticStage, DiagStage);
  return true;
}

bool SKEditorConsumer::handleDiagnostic(const DiagnosticEntryInfo &Info,
                                        UIdent DiagStage) {
  if (!EnableDiagnostics)
    return true;

  ResponseBuilder::Array &Arr = Diags;
  if (Arr.isNull())
    Arr = Dict.setArray(KeyDiagnostics);

  auto Elem = Arr.appendDictionary();
  UIdent SeverityUID;
  switch (Info.Severity) {
  case DiagnosticSeverityKind::Warning:
    SeverityUID = UIdent(KindDiagWarning.str());
    break;
  case DiagnosticSeverityKind::Error:
    SeverityUID = UIdent(KindDiagError.str());
    break;
  }

  Elem.set(KeySeverity, SeverityUID);
  Elem.set(KeyDiagnosticStage, DiagStage);
  fillDictionaryForDiagnosticInfo(Elem, Info);

  if (!Info.Notes.empty()) {
    auto NotesArr = Elem.setArray(KeyDiagnostics);
    for (auto &NoteDiag : Info.Notes) {
      auto NoteElem = NotesArr.appendDictionary();
      NoteElem.set(KeySeverity, KindDiagNote);
      fillDictionaryForDiagnosticInfo(NoteElem, NoteDiag);
    }
  }

  return true;
}

bool SKEditorConsumer::handleSourceText(StringRef Text) {
  Dict.set(KeySourceText, Text);
  return true;
}

static sourcekitd_response_t
editorFindUSR(StringRef DocumentName, StringRef USR) {
  ResponseBuilder RespBuilder;
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  llvm::Optional<std::pair<unsigned, unsigned>>
      Range = Lang.findUSRRange(DocumentName, USR);
  if (!Range) {
    // If cannot find the synthesized USR, find the actual USR instead.
    Range = Lang.findUSRRange(DocumentName,
                              USR.split(LangSupport::SynthesizedUSRSeparator).
                                first);
  }
  if (Range.hasValue()) {
    RespBuilder.getDictionary().set(KeyOffset, Range->first);
    RespBuilder.getDictionary().set(KeyLength, Range->second);
  }
  return RespBuilder.createResponse();
}

static sourcekitd_response_t
editorFindInterfaceDoc(StringRef ModuleName, ArrayRef<const char *> Args) {
  ResponseBuilder RespBuilder;
  sourcekitd_response_t Resp;
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.findInterfaceDocument(ModuleName, Args,
    [&](const InterfaceDocInfo &Info) {
      if (!Info.Error.empty()) {
        SmallString<128> Err(Info.Error);
        Resp = createErrorRequestFailed(Err.c_str());
        return;
      }

      auto Elem = RespBuilder.getDictionary();
      if (!Info.ModuleInterfaceName.empty())
        Elem.set(KeyModuleInterfaceName, Info.ModuleInterfaceName);
      if (!Info.CompilerArgs.empty())
        Elem.set(KeyCompilerArgs, Info.CompilerArgs);
      Resp = RespBuilder.createResponse();
    });

  return Resp;
}

static sourcekitd_response_t
editorFindModuleGroups(StringRef ModuleName, ArrayRef<const char *> Args) {
  ResponseBuilder RespBuilder;
  sourcekitd_response_t Resp;
  LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
  Lang.findModuleGroups(ModuleName, Args,
                        [&](ArrayRef<StringRef> Groups, StringRef Error) {
    if (!Error.empty()) {
      Resp = createErrorRequestFailed(Error.str().c_str());
      return;
    }
    auto Dict = RespBuilder.getDictionary();
    auto Arr = Dict.setArray(KeyModuleGroups);
    for (auto G : Groups) {
      auto Entry = Arr.appendDictionary();
      Entry.set(KeyGroupName, G);
    }
    Resp = RespBuilder.createResponse();
  });
  return Resp;
}

static bool isSemanticEditorDisabled() {
  enum class SemaInfoToggle : char {
    None, Disable, Enable
  };
  static SemaInfoToggle Toggle = SemaInfoToggle::None;

  if (Toggle == SemaInfoToggle::None) {
    static std::once_flag flag;
    std::call_once(flag, []() {
      Toggle = SemaInfoToggle::Enable;

      const char *EnvOpt = ::getenv("SOURCEKIT_DELAY_SEMA_EDITOR");
      if (!EnvOpt) {
        return;
      }

      unsigned Seconds;
      if (StringRef(EnvOpt).getAsInteger(10, Seconds))
        return;

      // A crash occurred previously. Disable semantic info in the editor for
      // the given amount, to avoid repeated crashers.
      LOG_WARN_FUNC("delaying semantic editor for " << Seconds << " seconds");
      Toggle = SemaInfoToggle::Disable;
      dispatch_time_t When = dispatch_time(DISPATCH_TIME_NOW,
                                           NSEC_PER_SEC * Seconds);
      dispatch_after(When, dispatch_get_main_queue(), ^{
        Toggle = SemaInfoToggle::Enable;
      });
    });
  }

  assert(Toggle != SemaInfoToggle::None);
  return Toggle == SemaInfoToggle::Disable;
}
