| //===--- 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/JSONSerialization.h" |
| #include "swift/IDE/APIDigesterData.h" |
| |
| using namespace swift; |
| using namespace ide; |
| using namespace api; |
| |
| inline raw_ostream &swift::ide::api:: |
| operator<<(raw_ostream &Out, const SDKNodeKind Value) { |
| switch (Value) { |
| #define NODE_KIND(Name) case SDKNodeKind::Name: return Out << #Name; |
| #include "swift/IDE/DigesterEnums.def" |
| } |
| llvm_unreachable("Undefined SDK node kind."); |
| } |
| |
| inline 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."); |
| } |
| |
| SDKNodeKind swift::ide::api::parseSDKNodeKind(StringRef Content) { |
| return llvm::StringSwitch<SDKNodeKind>(Content) |
| #define NODE_KIND(NAME) .Case(#NAME, SDKNodeKind::NAME) |
| #include "swift/IDE/DigesterEnums.def" |
| ; |
| } |
| |
| NodeAnnotation swift::ide::api::parseSDKNodeAnnotation(StringRef Content) { |
| return llvm::StringSwitch<NodeAnnotation>(Content) |
| #define NODE_ANNOTATION(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, ":"); |
| std::transform(Pieces.begin(), Pieces.end(), |
| std::back_inserter(ChildIndexPieces), |
| [](StringRef Piece) { return std::stoi(Piece); }); |
| } |
| |
| 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()){ |
| assert(NewName.argSize() == OldName.argSize()); |
| return TypeMemberDiffItemSubKind::SimpleReplacement; |
| } 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.hasValue() ? |
| std::to_string(selfIndex.getValue()) : ""; |
| 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; |
| } |
| } |
| |
| 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" |
| } |
| } |
| |
| 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()); |
| }; |
| |
| 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) 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: { |
| Optional<uint8_t> SelfIndexShort; |
| Optional<uint8_t> RemovedIndexShort; |
| if (SelfIndex) |
| SelfIndexShort = SelfIndex.getValue(); |
| if (RemovedIndex) |
| RemovedIndexShort = RemovedIndex.getValue(); |
| 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.getValue()); |
| } |
| case APIDiffItemKind::ADK_OverloadedFuncInfo: { |
| return new (Alloc.Allocate<OverloadedFuncInfo>()) OverloadedFuncInfo(Usr); |
| } |
| case APIDiffItemKind::ADK_SpecialCaseDiffItem: { |
| return new (Alloc.Allocate<SpecialCaseDiffItem>()) |
| SpecialCaseDiffItem(Usr, SpecialCaseId); |
| } |
| } |
| } |
| } // 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]); |
| } |
| }; |
| } // namespace json |
| } // namespace swift |
| |
| void swift::ide::api::APIDiffItemStore:: |
| serialize(llvm::raw_ostream &os, ArrayRef<APIDiffItem*> Items) { |
| json::Output yout(os); |
| yout << Items; |
| } |
| |
| struct swift::ide::api::APIDiffItemStore::Implementation { |
| private: |
| llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 2> AllBuffer; |
| llvm::BumpPtrAllocator Allocator; |
| public: |
| 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) { |
| llvm_unreachable("Failed to read JSON file"); |
| } |
| 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 (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() : |
| Impl(*new Implementation()) {} |
| |
| 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; |
| } |