blob: 97c15e773dde76cccd16a976d292e071b0777b30 [file] [log] [blame]
//===--- 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"
#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.");
}
StringRef swift::ide::api::getDeclKindStr(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.");
}
raw_ostream &swift::ide::api::operator<<(raw_ostream &Out,
const DeclKind Value) {
return Out << getDeclKindStr(Value);
}
Optional<SDKNodeKind> swift::ide::api::parseSDKNodeKind(StringRef Content) {
return llvm::StringSwitch<Optional<SDKNodeKind>>(Content)
#define NODE_KIND(NAME, VALUE) .Case(#VALUE, SDKNodeKind::NAME)
#include "swift/IDE/DigesterEnums.def"
.Default(None)
;
}
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, ":");
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()) {
// 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.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;
}
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());
};
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);
}
}
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;
}