//===--- APIDigesterData.cpp - api digester data implementation -----------===//
//
// 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 "llvm/ADT/StringSet.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/MemoryBuffer.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/JSONSerialization.h"
#include "swift/IDE/APIDigesterData.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsDriver.h"

using namespace swift;
using namespace ide;
using namespace api;

raw_ostream &swift::ide::api::
operator<<(raw_ostream &Out, const SDKNodeKind Value) {
  switch (Value) {
#define NODE_KIND(Name, Value) case SDKNodeKind::Name: return Out << #Value;
#include "swift/IDE/DigesterEnums.def"
  }
  llvm_unreachable("Undefined SDK node kind.");
}

raw_ostream &swift::ide::api::
operator<<(raw_ostream &Out, const NodeAnnotation Value) {
#define NODE_ANNOTATION(X) if (Value == NodeAnnotation::X) { return Out << #X; }
#include "swift/IDE/DigesterEnums.def"
  llvm_unreachable("Undefined SDK node kind.");
}

static StringRef getDeclKindStrRaw(const DeclKind Value)  {
  switch (Value) {
#define DECL(X, PARENT) case DeclKind::X: return #X;
#include "swift/AST/DeclNodes.def"
  } 
  llvm_unreachable("Unhandled DeclKind in switch.");
}

StringRef swift::ide::api::getDeclKindStr(const DeclKind Value, bool lower) {
  if (lower) {
    switch (Value) {
#define DECL(X, PARENT) case DeclKind::X: {                                   \
    static std::string lowered = StringRef(#X).lower();                       \
    return lowered;                                                           \
    }
#include "swift/AST/DeclNodes.def"
    }
    llvm_unreachable("Unhandled DeclKind in switch.");
  } else {
    return getDeclKindStrRaw(Value);
  }
}

raw_ostream &swift::ide::api::operator<<(raw_ostream &Out, const DeclKind Value) {
  return Out << getDeclKindStrRaw(Value);
}

std::optional<SDKNodeKind>
swift::ide::api::parseSDKNodeKind(StringRef Content) {
  return llvm::StringSwitch<std::optional<SDKNodeKind>>(Content)
#define NODE_KIND(NAME, VALUE) .Case(#VALUE, SDKNodeKind::NAME)
#include "swift/IDE/DigesterEnums.def"
      .Default(std::nullopt);
}

NodeAnnotation swift::ide::api::parseSDKNodeAnnotation(StringRef Content) {
  return llvm::StringSwitch<NodeAnnotation>(Content)
#define NODE_ANNOTATION_CHANGE_KIND(NAME) .Case(#NAME, NodeAnnotation::NAME)
#include "swift/IDE/DigesterEnums.def"
  ;
}

SpecialCaseId swift::ide::api::parseSpecialCaseId(StringRef Content) {
  return llvm::StringSwitch<SpecialCaseId>(Content)
#define SPECIAL_CASE_ID(NAME) .Case(#NAME, SpecialCaseId::NAME)
#include "swift/IDE/DigesterEnums.def"
  ;
}

swift::ide::api::CommonDiffItem::
CommonDiffItem(SDKNodeKind NodeKind, NodeAnnotation DiffKind,
               StringRef ChildIndex, StringRef LeftUsr, StringRef RightUsr,
               StringRef LeftComment, StringRef RightComment,
               StringRef ModuleName) : NodeKind(NodeKind),
                 DiffKind(DiffKind), ChildIndex(ChildIndex), LeftUsr(LeftUsr),
                 RightUsr(RightUsr), LeftComment(LeftComment),
                 RightComment(RightComment), ModuleName(ModuleName) {
  assert(!ChildIndex.empty() && "Child index is empty.");
  llvm::SmallVector<StringRef, 4> Pieces;
  ChildIndex.split(Pieces, ":");
  llvm::transform(Pieces, std::back_inserter(ChildIndexPieces),
                  [](StringRef Piece) { return std::stoi(Piece.str()); });
}

StringRef swift::ide::api::CommonDiffItem::head() {
  return "SDK_CHANGE";
}

bool swift::ide::api::CommonDiffItem::operator<(CommonDiffItem Other) const {
  if (auto UsrCompare = LeftUsr.compare(Other.LeftUsr))
      return UsrCompare < 0;
  if (NodeKind != Other.NodeKind)
    return NodeKind < Other.NodeKind;
  if (DiffKind != Other.DiffKind)
    return DiffKind < Other.DiffKind;
  if (auto ChildCompare = ChildIndex.compare(Other.ChildIndex))
    return ChildCompare < 0;
  return false;
}

void swift::ide::api::CommonDiffItem::describe(llvm::raw_ostream &os) {
  os << "#ifndef " << head() << "\n";
  os << "#define " << head() << "(NODE_KIND, DIFF_KIND, CHILD_INDEX, LEFT_USR, "
                                "RIGHT_USR, LEFT_COMMENT, RIGHT_COMMENT, "
                                "MODULENAME)\n";
  os << "#endif\n";
}

void swift::ide::api::CommonDiffItem::undef(llvm::raw_ostream &os) {
  os << "#undef " << head() << "\n";
}

void swift::ide::api::CommonDiffItem::streamDef(llvm::raw_ostream &S) const {
  S << head() << "(" << NodeKind << ", " << DiffKind << ", \"" << ChildIndex
    << "\", \"" << LeftUsr << "\", \"" << RightUsr << "\", \""
    << LeftComment << "\", \"" << RightComment
    << "\", \"" << ModuleName << "\")";
}

StringRef swift::ide::api::TypeMemberDiffItem::head() {
  return "SDK_CHANGE_TYPE_MEMBER";
}

TypeMemberDiffItemSubKind
swift::ide::api::TypeMemberDiffItem::getSubKind() const {
  DeclNameViewer OldName = getOldName();
  DeclNameViewer NewName = getNewName();
  if (!OldName.isFunction()) {
    assert(!NewName.isFunction());
    if (oldTypeName.empty())
      return TypeMemberDiffItemSubKind::SimpleReplacement;
    else
      return TypeMemberDiffItemSubKind::QualifiedReplacement;
  }
  assert(OldName.isFunction());
  bool ToProperty = !NewName.isFunction();
  if (selfIndex) {
    if (removedIndex) {
      if (ToProperty)
        llvm_unreachable("unknown situation");
      else {
        assert(NewName.argSize() + 2 == OldName.argSize());
        return TypeMemberDiffItemSubKind::HoistSelfAndRemoveParam;
      }
    } else if (ToProperty) {
      assert(OldName.argSize() == 1);
      return TypeMemberDiffItemSubKind::HoistSelfAndUseProperty;
    } else if (oldTypeName.empty()) {
      assert(NewName.argSize() + 1 == OldName.argSize());
      return TypeMemberDiffItemSubKind::HoistSelfOnly;
    } else {
      assert(NewName.argSize() == OldName.argSize());
      return TypeMemberDiffItemSubKind::QualifiedReplacement;
    }
  } else if (ToProperty) {
    assert(OldName.argSize() == 0);
    assert(!removedIndex);
    return TypeMemberDiffItemSubKind::GlobalFuncToStaticProperty;
  } else if (oldTypeName.empty()) {
    // we can handle this as a simple function rename.
    assert(NewName.argSize() == OldName.argSize());
    return TypeMemberDiffItemSubKind::FuncRename;
  } else {
    assert(NewName.argSize() == OldName.argSize());
    return TypeMemberDiffItemSubKind::QualifiedReplacement;
  }
}

void swift::ide::api::TypeMemberDiffItem::describe(llvm::raw_ostream &os) {
  os << "#ifndef " << head() << "\n";
  os << "#define " << head() << "(USR, NEW_TYPE_NAME, NEW_PRINTED_NAME, "
                                "SELF_INDEX, OLD_PRINTED_NAME)\n";
  os << "#endif\n";
}

void swift::ide::api::TypeMemberDiffItem::undef(llvm::raw_ostream &os) {
  os << "#undef " << head() << "\n";
}

void swift::ide::api::TypeMemberDiffItem::streamDef(llvm::raw_ostream &os) const {
  std::string IndexContent = selfIndex.has_value() ?
    std::to_string(selfIndex.value()) : "";
  os << head() << "("
     << "\"" << usr << "\"" << ", "
     << "\"" << newTypeName << "\"" << ", "
     << "\"" << newPrintedName << "\"" << ", "
     << "\"" << IndexContent << "\"" << ", "
     << "\"" << oldPrintedName << "\""
     << ")";
}

bool swift::ide::api::TypeMemberDiffItem::
operator<(TypeMemberDiffItem Other) const {
  return usr.compare(Other.usr) < 0;
}

StringRef swift::ide::api::NoEscapeFuncParam::head() {
  return "NOESCAPE_FUNC_PARAM";
}

void swift::ide::api::NoEscapeFuncParam::describe(llvm::raw_ostream &os) {
  os << "#ifndef " << head() << "\n";
  os << "#define " << head() << "(USR, Index)\n";
  os << "#endif\n";
}

void swift::ide::api::NoEscapeFuncParam::undef(llvm::raw_ostream &os) {
  os << "#undef " << head() << "\n";
}

void swift::ide::api::NoEscapeFuncParam::
streamDef(llvm::raw_ostream &os) const {
  os << head() << "(" << "\"" << Usr << "\"" << ", "
     << "\"" << Index << "\"" << ")";
}

bool swift::ide::api::NoEscapeFuncParam::
operator<(NoEscapeFuncParam Other) const {
  if (Usr != Other.Usr)
    return Usr.compare(Other.Usr) < 0;
  return Index < Other.Index;
}

StringRef swift::ide::api::OverloadedFuncInfo::head() {
  return "OVERLOAD_FUNC_TRAILING_CLOSURE";
}

void swift::ide::api::OverloadedFuncInfo::describe(llvm::raw_ostream &os) {
  os << "#ifndef " << head() << "\n";
  os << "#define " << head() << "(USR)\n";
  os << "#endif\n";
}

void swift::ide::api::OverloadedFuncInfo::undef(llvm::raw_ostream &os) {
  os << "#undef " << head() << "\n";
}

void swift::ide::api::OverloadedFuncInfo::
streamDef(llvm::raw_ostream &os) const {
  os << head() << "(" << "\"" << Usr << "\"" << ")";
}

bool swift::ide::api::OverloadedFuncInfo::
operator<(OverloadedFuncInfo Other) const {
  return Usr.compare(Other.Usr) < 0;
}

#define DIFF_ITEM_KIND(NAME)                                                   \
bool swift::ide::api::NAME::classof(const APIDiffItem *D) {                    \
  return D->getKind() == APIDiffItemKind::ADK_##NAME;                          \
}
#include "swift/IDE/DigesterEnums.def"

bool APIDiffItem::operator==(const APIDiffItem &Other) const {
  if (getKind() != Other.getKind())
    return false;
  if (getKey() != Other.getKey())
    return false;
  switch(getKind()) {
  case APIDiffItemKind::ADK_CommonDiffItem: {
    auto *Left = static_cast<const CommonDiffItem*>(this);
    auto *Right = static_cast<const CommonDiffItem*>(&Other);
    return
      Left->DiffKind == Right->DiffKind &&
      Left->ChildIndex == Right->ChildIndex;
  }
  case APIDiffItemKind::ADK_NoEscapeFuncParam: {
    auto *Left = static_cast<const NoEscapeFuncParam*>(this);
    auto *Right = static_cast<const NoEscapeFuncParam*>(&Other);
    return Left->Index == Right->Index;
  }
  case APIDiffItemKind::ADK_TypeMemberDiffItem:
  case APIDiffItemKind::ADK_OverloadedFuncInfo:
  case APIDiffItemKind::ADK_SpecialCaseDiffItem:
    return true;
  }
  llvm_unreachable("unhandled kind");
}

namespace {
enum class DiffItemKeyKind {
#define DIFF_ITEM_KEY_KIND(NAME) KK_##NAME,
#include "swift/IDE/DigesterEnums.def"
};

static const char* getKeyContent(DiffItemKeyKind KK) {
  switch (KK) {
#define DIFF_ITEM_KEY_KIND(NAME) case DiffItemKeyKind::KK_##NAME: return #NAME;
#include "swift/IDE/DigesterEnums.def"
  }
  llvm_unreachable("unhandled kind");
}

static DiffItemKeyKind parseKeyKind(StringRef Content) {
  return llvm::StringSwitch<DiffItemKeyKind>(Content)
#define DIFF_ITEM_KEY_KIND(NAME) .Case(#NAME, DiffItemKeyKind::KK_##NAME)
#include "swift/IDE/DigesterEnums.def"
  ;
}

static APIDiffItemKind parseDiffItemKind(StringRef Content) {
  return llvm::StringSwitch<APIDiffItemKind>(Content)
#define DIFF_ITEM_KIND(NAME) .Case(#NAME, APIDiffItemKind::ADK_##NAME)
#include "swift/IDE/DigesterEnums.def"
  ;
}

static StringRef getScalarString(llvm::yaml::Node *N) {
  auto WithQuote = cast<llvm::yaml::ScalarNode>(N)->getRawValue();
  return WithQuote.substr(1, WithQuote.size() - 2);
}

static int getScalarInt(llvm::yaml::Node *N) {
  return std::stoi(cast<llvm::yaml::ScalarNode>(N)->getRawValue().str());
}

static APIDiffItem*
serializeDiffItem(llvm::BumpPtrAllocator &Alloc,
                  llvm::yaml::MappingNode* Node) {
#define DIFF_ITEM_KEY_KIND_STRING(NAME) StringRef NAME;
#define DIFF_ITEM_KEY_KIND_INT(NAME) std::optional<int> NAME;
#include "swift/IDE/DigesterEnums.def"
  for (auto &Pair : *Node) {
    switch(parseKeyKind(getScalarString(Pair.getKey()))) {
#define DIFF_ITEM_KEY_KIND_STRING(NAME)                                       \
    case DiffItemKeyKind::KK_##NAME:                                          \
      NAME = getScalarString(Pair.getValue()); break;
#define DIFF_ITEM_KEY_KIND_INT(NAME)                                          \
    case DiffItemKeyKind::KK_##NAME:                                          \
      NAME = getScalarInt(Pair.getValue()); break;
#include "swift/IDE/DigesterEnums.def"
    }
  }
  switch (parseDiffItemKind(DiffItemKind)) {
  case APIDiffItemKind::ADK_CommonDiffItem: {
    return new (Alloc.Allocate<CommonDiffItem>())
      CommonDiffItem(*parseSDKNodeKind(NodeKind),
                     parseSDKNodeAnnotation(NodeAnnotation), ChildIndex,
                     LeftUsr, RightUsr, LeftComment, RightComment, ModuleName);
  }
  case APIDiffItemKind::ADK_TypeMemberDiffItem: {
    std::optional<uint8_t> SelfIndexShort;
    std::optional<uint8_t> RemovedIndexShort;
    if (SelfIndex)
      SelfIndexShort = SelfIndex.value();
    if (RemovedIndex)
      RemovedIndexShort = RemovedIndex.value();
    return new (Alloc.Allocate<TypeMemberDiffItem>())
      TypeMemberDiffItem(Usr, NewTypeName, NewPrintedName, SelfIndexShort,
                         RemovedIndexShort, OldTypeName, OldPrintedName);
  }
  case APIDiffItemKind::ADK_NoEscapeFuncParam: {
    return new (Alloc.Allocate<NoEscapeFuncParam>())
      NoEscapeFuncParam(Usr, Index.value());
  }
  case APIDiffItemKind::ADK_OverloadedFuncInfo: {
    return new (Alloc.Allocate<OverloadedFuncInfo>()) OverloadedFuncInfo(Usr);
  }
  case APIDiffItemKind::ADK_SpecialCaseDiffItem: {
    return new (Alloc.Allocate<SpecialCaseDiffItem>())
      SpecialCaseDiffItem(Usr, SpecialCaseId);
  }
  }
  llvm_unreachable("unhandled kind");
}
} // end anonymous namespace

namespace swift {
namespace json {
template<>
struct ScalarEnumerationTraits<APIDiffItemKind> {
  static void enumeration(Output &out, APIDiffItemKind &value) {
#define DIFF_ITEM_KIND(X) out.enumCase(value, #X, APIDiffItemKind::ADK_##X);
#include "swift/IDE/DigesterEnums.def"
  }
};

template<>
struct ScalarEnumerationTraits<NodeAnnotation> {
  static void enumeration(Output &out, NodeAnnotation &value) {
#define NODE_ANNOTATION(X) out.enumCase(value, #X, NodeAnnotation::X);
#include "swift/IDE/DigesterEnums.def"
  }
};
template<>
struct ObjectTraits<APIDiffItem*> {
  static void mapping(Output &out, APIDiffItem *&value) {
    switch (value->getKind()) {
    case APIDiffItemKind::ADK_CommonDiffItem: {
      CommonDiffItem *Item = cast<CommonDiffItem>(value);
      auto ItemKind = Item->getKind();
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_DiffItemKind), ItemKind);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_NodeKind),
                      Item->NodeKind);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_NodeAnnotation),
                      Item->DiffKind);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_ChildIndex),
                      Item->ChildIndex);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_LeftUsr),
                      Item->LeftUsr);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_LeftComment),
                      Item->LeftComment);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_RightUsr),
                      Item->RightUsr);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_RightComment),
                      Item->RightComment);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_ModuleName),
                      Item->ModuleName);
      return;
    }
    case APIDiffItemKind::ADK_TypeMemberDiffItem: {
      TypeMemberDiffItem *Item = cast<TypeMemberDiffItem>(value);
      auto ItemKind = Item->getKind();
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_DiffItemKind),
                      ItemKind);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_Usr), Item->usr);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_OldPrintedName),
                      Item->oldPrintedName);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_OldTypeName),
                      Item->oldTypeName);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_NewPrintedName),
                      Item->newPrintedName);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_NewTypeName),
                      Item->newTypeName);
      out.mapOptional(getKeyContent(DiffItemKeyKind::KK_SelfIndex),
                      Item->selfIndex);
      return;
    }
    case APIDiffItemKind::ADK_NoEscapeFuncParam: {
      NoEscapeFuncParam *Item = cast<NoEscapeFuncParam>(value);
      auto ItemKind = Item->getKind();
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_DiffItemKind), ItemKind);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_Usr), Item->Usr);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_Index), Item->Index);
      return;
    }
    case APIDiffItemKind::ADK_OverloadedFuncInfo: {
      OverloadedFuncInfo *Item = cast<OverloadedFuncInfo>(value);
      auto ItemKind = Item->getKind();
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_DiffItemKind), ItemKind);
      out.mapRequired(getKeyContent(DiffItemKeyKind::KK_Usr), Item->Usr);
      return;
    }
    case APIDiffItemKind::ADK_SpecialCaseDiffItem:
      llvm_unreachable("This entry should be authored only.");
    }
  }
};
template<>
struct ArrayTraits<ArrayRef<APIDiffItem*>> {
  static size_t size(Output &out, ArrayRef<APIDiffItem *> &seq) {
    return seq.size();
  }
  static APIDiffItem *&element(Output &, ArrayRef<APIDiffItem *> &seq,
                               size_t index) {
    return const_cast<APIDiffItem *&>(seq[index]);
  }
};

template<>
struct ObjectTraits<NameCorrectionInfo> {
  static void mapping(Output &out, NameCorrectionInfo &value) {
    out.mapRequired(getKeyContent(DiffItemKeyKind::KK_OldPrintedName),value.OriginalName);
    out.mapRequired(getKeyContent(DiffItemKeyKind::KK_NewPrintedName), value.CorrectedName);
    out.mapRequired(getKeyContent(DiffItemKeyKind::KK_ModuleName), value.ModuleName);
  }
};
template<>
struct ArrayTraits<ArrayRef<NameCorrectionInfo>> {
  static size_t size(Output &out, ArrayRef<NameCorrectionInfo> &seq) {
    return seq.size();
  }
  static NameCorrectionInfo &element(Output &, ArrayRef<NameCorrectionInfo> &seq,
                                     size_t index) {
    return const_cast<NameCorrectionInfo&>(seq[index]);
  }
};
} // namespace json
} // namespace swift

void swift::ide::api::APIDiffItemStore::
serialize(llvm::raw_ostream &os, ArrayRef<APIDiffItem*> Items) {
  json::Output yout(os);
  yout << Items;
}

void swift::ide::api::APIDiffItemStore::
serialize(llvm::raw_ostream &os, ArrayRef<NameCorrectionInfo> Items) {
  json::Output yout(os);
  yout << Items;
}

struct swift::ide::api::APIDiffItemStore::Implementation {
private:
  DiagnosticEngine &Diags;
  llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 2> AllBuffer;
  llvm::BumpPtrAllocator Allocator;

  static bool shouldInclude(APIDiffItem *Item) {
    if (auto *CI = dyn_cast<CommonDiffItem>(Item)) {
      if (CI->rightCommentUnderscored())
        return false;

      // Ignore constructor's return value rewritten.
      if (CI->DiffKind == NodeAnnotation::TypeRewritten &&
          CI->NodeKind == SDKNodeKind::DeclConstructor &&
          CI->getChildIndices().front() == 0) {
        return false;
      }
    }
    return true;
  }

public:
  Implementation(DiagnosticEngine &Diags): Diags(Diags) {}
  llvm::StringMap<std::vector<APIDiffItem*>> Data;
  bool PrintUsr;
  std::vector<APIDiffItem*> AllItems;
  llvm::StringSet<> PrintedUsrs;
  void addStorePath(StringRef FileName) {
    llvm::MemoryBuffer *pMemBuffer = nullptr;
    {
      auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(FileName);
      if (!FileBufOrErr) {
        Diags.diagnose(SourceLoc(), diag::cannot_find_migration_script,
          FileName);
        return;
      }
      pMemBuffer = FileBufOrErr->get();
      AllBuffer.push_back(std::move(FileBufOrErr.get()));
    }
    assert(pMemBuffer);
    StringRef Buffer = pMemBuffer->getBuffer();
    llvm::SourceMgr SM;
    llvm::yaml::Stream Stream(Buffer, SM);
    for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) {
      auto Array = cast<llvm::yaml::SequenceNode>(DI->getRoot());
      for (auto It = Array->begin(); It != Array->end(); ++ It) {
        APIDiffItem *Item = serializeDiffItem(Allocator,
          cast<llvm::yaml::MappingNode>(&*It));
        auto &Bag = Data[Item->getKey()];
        if (shouldInclude(Item) && std::find_if(Bag.begin(), Bag.end(),
            [&](APIDiffItem* I) { return *Item == *I; }) == Bag.end()) {
          Bag.push_back(Item);
          AllItems.push_back(Item);
        }
      }
    }
  }
};

ArrayRef<APIDiffItem*> swift::ide::api::APIDiffItemStore::
getDiffItems(StringRef Key) const {
  if (Impl.PrintUsr && !Impl.PrintedUsrs.count(Key)) {
    llvm::outs() << Key << "\n";
    Impl.PrintedUsrs.insert(Key);
  }
  return Impl.Data[Key];
}

ArrayRef<APIDiffItem*> swift::ide::api::APIDiffItemStore::
getAllDiffItems() const { return Impl.AllItems; }

swift::ide::api::APIDiffItemStore::APIDiffItemStore(DiagnosticEngine &Diags) :
  Impl(*new Implementation(Diags)) {}

swift::ide::api::APIDiffItemStore::~APIDiffItemStore() { delete &Impl; }

void swift::ide::api::APIDiffItemStore::addStorePath(StringRef Path) {
  Impl.addStorePath(Path);
}

void swift::ide::api::APIDiffItemStore::printIncomingUsr(bool print) {
  Impl.PrintUsr = print;
}