Files
swift-mirror/lib/IDE/APIDigesterData.cpp
Xi Ge 824aaa11e2 swift-api-digester: detect the move of static members only.
This patch restricts the detection of moved members to be static members,
since only in this case we need to update qualified access to
them. The move of instance members will be either handled by rename or
we don't need to update anything at all.

Additionally, this patch introduces a sub-kind of type member diff item
called qualified replacement to describe the aforementioned case. However,
the migrator part has not started to honor this sub-kind yet.

rdar://32466196
2017-05-31 11:47:27 -07:00

512 lines
18 KiB
C++

//===--- 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());
return TypeMemberDiffItemSubKind::SimpleReplacement;
}
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 {
assert(NewName.argSize() == OldName.argSize());
return TypeMemberDiffItemSubKind::SimpleReplacement;
}
}
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->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;
}