mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge remote-tracking branch 'origin/master' into master-next
This commit is contained in:
@@ -1,25 +1,25 @@
|
||||
//===--- swift-api-digester.cpp - API change detector -------===//
|
||||
////
|
||||
//// This source file is part of the Swift.org open source project
|
||||
////
|
||||
//// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
//// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
////
|
||||
//// See http://swift.org/LICENSE.txt for license information
|
||||
//// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
////
|
||||
////===----------------------------------------------------------------------===//
|
||||
//===--- swift-api-digester.cpp - API change detector ---------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// swift-api-digester is a test utility to detect source-breaking API changes
|
||||
// during the evolution of a swift library. The tool works on two phases:
|
||||
// (1) dumping library contents as a json file, and (2) comparing two json
|
||||
// during the evolution of a Swift library. The tool works on two phases:
|
||||
// (1) dumping library contents as a JSON file, and (2) comparing two JSON
|
||||
// files textually to report interesting changes.
|
||||
//
|
||||
// During phase (1), the api-digester looks up every declarations inside
|
||||
// a module and outputs a singly-rooted tree that encloses interesting
|
||||
// details of the API level.
|
||||
//
|
||||
// During phase (2), api-digester applies structure-information comparision
|
||||
// During phase (2), api-digester applies structure-information comparison
|
||||
// algorithms on two given singly root trees, trying to figure out, as
|
||||
// precise as possible, the branches/leaves in the trees that differ from
|
||||
// each other. Further analysis decides whether the changed leaves/branches
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "swift/AST/PrettyStackTrace.h"
|
||||
#include "swift/AST/USRGeneration.h"
|
||||
#include "swift/Basic/ColorUtils.h"
|
||||
#include "swift/Basic/Fallthrough.h"
|
||||
#include "swift/Basic/JSONSerialization.h"
|
||||
#include "swift/Basic/LLVMInitialize.h"
|
||||
#include "swift/Basic/STLExtras.h"
|
||||
@@ -77,7 +78,7 @@ ModuleNames("module", llvm::cl::ZeroOrMore, llvm::cl::desc("Names of modules"));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
ModuleList("module-list-file",
|
||||
llvm::cl::desc("File containing new-line separated list of modules"));
|
||||
llvm::cl::desc("File containing a new-line separated list of modules"));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
OutputFile("o", llvm::cl::desc("Output file"));
|
||||
@@ -98,6 +99,12 @@ ResourceDir("resource-dir",
|
||||
static llvm::cl::list<std::string>
|
||||
FrameworkPaths("F", llvm::cl::desc("add a directory to the framework search path"));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
ModuleInputPaths("I", llvm::cl::desc("add a module for input"));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
CCSystemFrameworkPaths("iframework", llvm::cl::desc("add a directory to the clang importer system framework search path"));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
AbortOnModuleLoadFailure("abort-on-module-fail",
|
||||
llvm::cl::desc("Abort if a module failed to load"));
|
||||
@@ -110,20 +117,20 @@ Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None),
|
||||
llvm::cl::values(
|
||||
clEnumValN(ActionType::DumpSDK,
|
||||
"dump-sdk",
|
||||
"Dump SDK content to json file"),
|
||||
"Dump SDK content to JSON file"),
|
||||
clEnumValN(ActionType::DumpSwiftModules,
|
||||
"dump-swift",
|
||||
"dump swift modules in SDK"),
|
||||
clEnumValN(ActionType::CompareSDKs,
|
||||
"compare-sdk",
|
||||
"Compare SDK content in json file"),
|
||||
"Compare SDK content in JSON file"),
|
||||
clEnumValN(ActionType::DiagnoseSDKs,
|
||||
"diagnose-sdk",
|
||||
"Diagnose SDK content in json file")));
|
||||
"Diagnose SDK content in JSON file")));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
SDKJsonPaths("input-paths",
|
||||
llvm::cl::desc("The SDK contents under conparison"));
|
||||
llvm::cl::desc("The SDK contents under comparison"));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
ApisPrintUsrs("api-usrs",
|
||||
@@ -137,7 +144,7 @@ IgnoreRemovedDeclUSRs("ignored-usrs",
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
SwiftVersion("swift-version",
|
||||
llvm::cl::desc("The swift compiler version to invoke"));
|
||||
llvm::cl::desc("The Swift compiler version to invoke"));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -191,7 +198,6 @@ public:
|
||||
struct MatchedNodeListener {
|
||||
virtual void foundMatch(NodePtr Left, NodePtr Right) = 0;
|
||||
virtual void foundRemoveAddMatch(NodePtr Removed, NodePtr Added) {}
|
||||
virtual bool isMatched(NodePtr Left, NodePtr Right) {return false;};
|
||||
virtual ~MatchedNodeListener() = default;
|
||||
};
|
||||
|
||||
@@ -204,7 +210,7 @@ struct NodeMatcher {
|
||||
#define KEY(NAME) static const char* Key_##NAME = #NAME;
|
||||
#include "DigesterEnums.def"
|
||||
|
||||
// The node kind apparing in the tree that describes the content of the SDK
|
||||
// The node kind appearing in the tree that describes the content of the SDK
|
||||
enum class SDKNodeKind {
|
||||
#define NODE_KIND(NAME) NAME,
|
||||
#include "DigesterEnums.def"
|
||||
@@ -257,6 +263,7 @@ struct SDKNodeInitInfo {
|
||||
StringRef Location;
|
||||
StringRef ModuleName;
|
||||
bool IsThrowing = false;
|
||||
bool IsMutating = false;
|
||||
Optional<uint8_t> SelfIndex;
|
||||
std::vector<SDKDeclAttrKind> DeclAttrs;
|
||||
std::vector<TypeAttrKind> TypeAttrs;
|
||||
@@ -295,9 +302,7 @@ public:
|
||||
StringRef getPrintedName() const { return PrintedName; }
|
||||
void removeChild(ChildIt CI) { Children.erase(CI); }
|
||||
ChildIt getChildBegin() const { return Children.begin(); }
|
||||
ChildIt getChildEnd() const { return Children.end(); }
|
||||
void annotate(NodeAnnotation Anno) { Annotations.insert(Anno); }
|
||||
bool isName(StringRef N) const { return getName() == N; }
|
||||
NodePtr getParent() const { return Parent; };
|
||||
unsigned getChildrenCount() const { return Children.size(); }
|
||||
NodePtr childAt(unsigned I) const;
|
||||
@@ -356,7 +361,6 @@ public:
|
||||
ArrayRef<TypeAttrKind> getTypeAttributes() const;
|
||||
SDKNodeDecl *getClosestParentDecl() const;
|
||||
static bool classof(const SDKNode *N);
|
||||
static bool areTypesSame(const SDKNodeType *Left, const SDKNodeType *Right);
|
||||
};
|
||||
|
||||
bool SDKNodeType::classof(const SDKNode *N) {
|
||||
@@ -460,54 +464,33 @@ void SDKNode::postorderVisit(NodePtr Root, SDKNodeVisitor &Visitor) {
|
||||
Visitor.visit(Root);
|
||||
}
|
||||
|
||||
bool SDKNode::operator==(const SDKNode &Other) const {
|
||||
if (getKind() != Other.getKind())
|
||||
return false;
|
||||
|
||||
// Using type's equal algorithm
|
||||
if (auto *T1 = dyn_cast<SDKNodeType>(this)) {
|
||||
return SDKNodeType::areTypesSame(T1, (&Other)->getAs<SDKNodeType>());
|
||||
}
|
||||
|
||||
if (getPrintedName() == Other.getPrintedName() &&
|
||||
Children.size() == Other.Children.size()) {
|
||||
for (unsigned long I = 0; I < Children.size(); I ++) {
|
||||
if ((*Children[I]) == (*Other.Children[I]))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class SDKNodeVectorViewer {
|
||||
ArrayRef<SDKNode*> Collection;
|
||||
llvm::function_ref<bool(NodePtr)> Selector;
|
||||
typedef ArrayRef<SDKNode*>::const_iterator VectorIt;
|
||||
VectorIt getNext(VectorIt Start);
|
||||
class ViwerIterator;
|
||||
class ViewerIterator;
|
||||
|
||||
public:
|
||||
SDKNodeVectorViewer(ArrayRef<SDKNode*> Collection,
|
||||
llvm::function_ref<bool(NodePtr)> Selector) :
|
||||
Collection(Collection),
|
||||
Selector(Selector) {}
|
||||
ViwerIterator begin();
|
||||
ViwerIterator end();
|
||||
ViewerIterator begin();
|
||||
ViewerIterator end();
|
||||
};
|
||||
|
||||
class SDKNodeVectorViewer::ViwerIterator :
|
||||
class SDKNodeVectorViewer::ViewerIterator :
|
||||
public std::iterator<std::input_iterator_tag, VectorIt> {
|
||||
SDKNodeVectorViewer &Viewer;
|
||||
VectorIt P;
|
||||
public:
|
||||
ViwerIterator(SDKNodeVectorViewer &Viewer, VectorIt P) : Viewer(Viewer), P(P) {}
|
||||
ViwerIterator(const ViwerIterator& mit) : Viewer(mit.Viewer), P(mit.P) {}
|
||||
ViwerIterator& operator++();
|
||||
ViwerIterator operator++(int) {ViwerIterator tmp(*this); operator++(); return tmp;}
|
||||
bool operator==(const ViwerIterator& rhs) {return P==rhs.P;}
|
||||
bool operator!=(const ViwerIterator& rhs) {return P!=rhs.P;}
|
||||
ViewerIterator(SDKNodeVectorViewer &Viewer, VectorIt P) : Viewer(Viewer), P(P) {}
|
||||
ViewerIterator(const ViewerIterator& mit) : Viewer(mit.Viewer), P(mit.P) {}
|
||||
ViewerIterator& operator++();
|
||||
ViewerIterator operator++(int) {ViewerIterator tmp(*this); operator++(); return tmp;}
|
||||
bool operator==(const ViewerIterator& rhs) {return P==rhs.P;}
|
||||
bool operator!=(const ViewerIterator& rhs) {return P!=rhs.P;}
|
||||
const NodePtr& operator*() {return *P;}
|
||||
};
|
||||
|
||||
@@ -519,18 +502,18 @@ SDKNodeVectorViewer::getNext(VectorIt Start) {
|
||||
return Collection.end();
|
||||
}
|
||||
|
||||
SDKNodeVectorViewer::ViwerIterator&
|
||||
SDKNodeVectorViewer::ViwerIterator::operator++() {
|
||||
SDKNodeVectorViewer::ViewerIterator&
|
||||
SDKNodeVectorViewer::ViewerIterator::operator++() {
|
||||
P = Viewer.getNext(P + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SDKNodeVectorViewer::ViwerIterator SDKNodeVectorViewer::begin() {
|
||||
return ViwerIterator(*this, getNext(Collection.begin()));
|
||||
SDKNodeVectorViewer::ViewerIterator SDKNodeVectorViewer::begin() {
|
||||
return ViewerIterator(*this, getNext(Collection.begin()));
|
||||
}
|
||||
|
||||
SDKNodeVectorViewer::ViwerIterator SDKNodeVectorViewer::end() {
|
||||
return ViwerIterator(*this, Collection.end());
|
||||
SDKNodeVectorViewer::ViewerIterator SDKNodeVectorViewer::end() {
|
||||
return ViewerIterator(*this, Collection.end());
|
||||
}
|
||||
|
||||
class SDKNodeDecl;
|
||||
@@ -646,17 +629,6 @@ SDKNodeDecl *SDKNodeType::getClosestParentDecl() const {
|
||||
return Result->getAs<SDKNodeDecl>();
|
||||
}
|
||||
|
||||
bool SDKNodeType::areTypesSame(const SDKNodeType *Left,
|
||||
const SDKNodeType *Right) {
|
||||
if (Left->getTypeAttributes().size() != Right->getTypeAttributes().size())
|
||||
return false;
|
||||
for (auto L : Left->getTypeAttributes()) {
|
||||
if (!contains(Right->getTypeAttributes(), L))
|
||||
return false;
|
||||
}
|
||||
return Left->getPrintedName() == Right->getPrintedName();
|
||||
}
|
||||
|
||||
class SDKNodeTypeDecl : public SDKNodeDecl {
|
||||
public:
|
||||
SDKNodeTypeDecl(SDKNodeInitInfo Info) : SDKNodeDecl(Info,
|
||||
@@ -679,15 +651,18 @@ public:
|
||||
|
||||
class SDKNodeAbstractFunc : public SDKNodeDecl {
|
||||
const bool IsThrowing;
|
||||
const bool IsMutating;
|
||||
const Optional<uint8_t> SelfIndex;
|
||||
|
||||
protected:
|
||||
SDKNodeAbstractFunc(SDKNodeInitInfo Info, SDKNodeKind Kind) :
|
||||
SDKNodeDecl(Info, Kind),
|
||||
IsThrowing(Info.IsThrowing),
|
||||
IsMutating(Info.IsMutating),
|
||||
SelfIndex(Info.SelfIndex){}
|
||||
public:
|
||||
bool isThrowing() const { return IsThrowing; }
|
||||
bool isMutating() const { return IsMutating; }
|
||||
uint8_t getSelfIndex() const { return SelfIndex.getValue(); }
|
||||
Optional<uint8_t> getSelfIndexOptional() const { return SelfIndex; }
|
||||
bool hasSelfIndex() const { return SelfIndex.hasValue(); }
|
||||
@@ -796,6 +771,8 @@ NodeUniquePtr SDKNode::constructSDKNode(llvm::yaml::MappingNode *Node) {
|
||||
Info.ModuleName = GetScalarString(Pair.getValue());
|
||||
} else if (Key == Key_throwing) {
|
||||
Info.IsThrowing = true;
|
||||
} else if (Key == Key_mutating) {
|
||||
Info.IsMutating = true;
|
||||
} else if (Key == Key_typeAttributes) {
|
||||
auto *Seq = cast<llvm::yaml::SequenceNode>(Pair.getValue());
|
||||
for (auto It = Seq->begin(); It != Seq->end(); ++ It) {
|
||||
@@ -830,6 +807,77 @@ NodeUniquePtr SDKNode::constructSDKNode(llvm::yaml::MappingNode *Node) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// This is for caching the comparison results between two SDKNodes.
|
||||
class SDKNodeEqualContext {
|
||||
using NodePtrAndEqual = llvm::DenseMap<const SDKNode*, bool>;
|
||||
llvm::DenseMap<const SDKNode*, llvm::DenseMap<const SDKNode*, bool>> Data;
|
||||
|
||||
public:
|
||||
Optional<bool> getEquality(const SDKNode* Left, const SDKNode* Right) {
|
||||
auto &Map = Data.insert({Left, NodePtrAndEqual()}).first->getSecond();
|
||||
if (Map.count(Right))
|
||||
return Map[Right];
|
||||
return None;
|
||||
}
|
||||
|
||||
void addEquality(const SDKNode* Left, const SDKNode* Right, const bool Value) {
|
||||
Data.insert(std::make_pair(Left, NodePtrAndEqual())).first->getSecond().
|
||||
insert({Right, Value});
|
||||
}
|
||||
};
|
||||
|
||||
bool SDKNode::operator==(const SDKNode &Other) const {
|
||||
static SDKNodeEqualContext EqualCache;
|
||||
if (auto Cached = EqualCache.getEquality(this, &Other)) {
|
||||
return Cached.getValue();
|
||||
}
|
||||
auto Exit = [&](const bool Result) {
|
||||
EqualCache.addEquality(this, &Other, Result);
|
||||
return Result;
|
||||
};
|
||||
|
||||
if (getKind() != Other.getKind())
|
||||
return Exit(false);
|
||||
|
||||
switch(getKind()) {
|
||||
case SDKNodeKind::TypeNominal:
|
||||
case SDKNodeKind::TypeFunc: {
|
||||
auto Left = this->getAs<SDKNodeType>();
|
||||
auto Right = (&Other)->getAs<SDKNodeType>();
|
||||
return Exit(Left->getTypeAttributes().equals(Right->getTypeAttributes())
|
||||
&& Left->getPrintedName() == Right->getPrintedName());
|
||||
}
|
||||
|
||||
case SDKNodeKind::Function:
|
||||
case SDKNodeKind::Constructor:
|
||||
case SDKNodeKind::Getter:
|
||||
case SDKNodeKind::Setter: {
|
||||
auto Left = this->getAs<SDKNodeAbstractFunc>();
|
||||
auto Right = (&Other)->getAs<SDKNodeAbstractFunc>();
|
||||
if (Left->isMutating() ^ Right->isMutating())
|
||||
return Exit(false);
|
||||
if (Left->isThrowing() ^ Right->isThrowing())
|
||||
return Exit(false);
|
||||
SWIFT_FALLTHROUGH;
|
||||
}
|
||||
case SDKNodeKind::TypeDecl:
|
||||
case SDKNodeKind::Var:
|
||||
case SDKNodeKind::TypeAlias:
|
||||
case SDKNodeKind::Root:
|
||||
case SDKNodeKind::Nil: {
|
||||
if (getPrintedName() == Other.getPrintedName() &&
|
||||
Children.size() == Other.Children.size()) {
|
||||
for (unsigned I = 0; I < Children.size(); ++ I) {
|
||||
if (*Children[I] != *Other.Children[I])
|
||||
return Exit(false);
|
||||
}
|
||||
return Exit(true);
|
||||
}
|
||||
return Exit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The pretty printer of a tree of SDKNode
|
||||
class SDKNodeDumpVisitor : public SDKNodeVisitor {
|
||||
void dumpSpace(int Num) {
|
||||
@@ -846,15 +894,6 @@ public:
|
||||
SDKNodeDumpVisitor() {};
|
||||
};
|
||||
|
||||
class DumpMatchListener : public MatchedNodeListener {
|
||||
void foundMatch(NodePtr Left, NodePtr Right) override {
|
||||
llvm::outs() << Left->getName() << "->" << Right->getName() << "\n";
|
||||
};
|
||||
bool isMatched(NodePtr Left, NodePtr Right) override {
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
static StringRef getPrintedName(Type Ty) {
|
||||
std::string S;
|
||||
llvm::raw_string_ostream OS(S);
|
||||
@@ -942,6 +981,13 @@ static bool isFuncThrowing(ValueDecl *VD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isFuncMutating(ValueDecl *VD) {
|
||||
if (auto AF = dyn_cast<FuncDecl>(VD)) {
|
||||
return AF->isMutating();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Optional<uint8_t> getSelfIndex(ValueDecl *VD) {
|
||||
if (auto AF = dyn_cast<AbstractFunctionDecl>(VD)) {
|
||||
if (AF->isImportAsInstanceMember())
|
||||
@@ -961,7 +1007,8 @@ SDKNodeInitInfo::SDKNodeInitInfo(ValueDecl *VD) :
|
||||
PrintedName(getPrintedName(VD)), DKind(VD->getKind()),
|
||||
USR(calculateUsr(VD)), Location(calculateLocation(VD)),
|
||||
ModuleName(VD->getModuleContext()->getName().str()),
|
||||
IsThrowing(isFuncThrowing(VD)), SelfIndex(getSelfIndex(VD)) {
|
||||
IsThrowing(isFuncThrowing(VD)), IsMutating(isFuncMutating(VD)),
|
||||
SelfIndex(getSelfIndex(VD)) {
|
||||
if (VD->getAttrs().getDeprecated(VD->getASTContext()))
|
||||
DeclAttrs.push_back(SDKDeclAttrKind::DAK_deprecated);
|
||||
}
|
||||
@@ -979,7 +1026,7 @@ case SDKNodeKind::X: \
|
||||
}
|
||||
|
||||
// Recursively construct a node that represents a type, for instance,
|
||||
// representing the the return value type of a function decl.
|
||||
// representing the return value type of a function decl.
|
||||
static NodeUniquePtr constructTypeNode(Type T) {
|
||||
NodeUniquePtr Root = SDKNodeInitInfo(T).createSDKNode(SDKNodeKind::TypeNominal);
|
||||
|
||||
@@ -1153,7 +1200,7 @@ public:
|
||||
RootNode = std::move(Pair.second);
|
||||
}
|
||||
|
||||
// Serialize the content of all roots to a given file using json format.
|
||||
// Serialize the content of all roots to a given file using JSON format.
|
||||
void serialize(StringRef Filename) {
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream fs(Filename, EC, llvm::sys::fs::F_None);
|
||||
@@ -1161,7 +1208,7 @@ public:
|
||||
}
|
||||
|
||||
// After collecting decls, either from imported modules or from a previously
|
||||
// serialized json file, using this function to get the root of the SDK.
|
||||
// serialized JSON file, using this function to get the root of the SDK.
|
||||
NodePtr getSDKRoot() {
|
||||
return RootNode.get();
|
||||
}
|
||||
@@ -1232,7 +1279,7 @@ public:
|
||||
namespace swift {
|
||||
namespace json {
|
||||
// In the namespace of swift::json, we define several functions so that the
|
||||
// json serializer will know how to interpret and dump types defined in this
|
||||
// JSON serializer will know how to interpret and dump types defined in this
|
||||
// file.
|
||||
template<>
|
||||
struct ScalarEnumerationTraits<SDKNodeKind> {
|
||||
@@ -1292,6 +1339,8 @@ namespace swift {
|
||||
if (auto F = dyn_cast<SDKNodeAbstractFunc>(value.get())) {
|
||||
if (bool isThrowing = F->isThrowing())
|
||||
out.mapRequired(Key_throwing, isThrowing);
|
||||
if (bool isMutating = F->isMutating())
|
||||
out.mapRequired(Key_mutating, isMutating);
|
||||
if (F->hasSelfIndex()) {
|
||||
auto Index = F->getSelfIndex();
|
||||
out.mapRequired(Key_selfIndex, Index);
|
||||
@@ -1364,7 +1413,7 @@ parseJsonEmit(StringRef FileName) {
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
|
||||
llvm::MemoryBuffer::getFileOrSTDIN(FileName);
|
||||
if (!FileBufOrErr) {
|
||||
llvm_unreachable("Failed to read json file");
|
||||
llvm_unreachable("Failed to read JSON file");
|
||||
}
|
||||
StringRef Buffer = FileBufOrErr->get()->getBuffer();
|
||||
llvm::SourceMgr SM;
|
||||
@@ -1681,7 +1730,7 @@ class SameNameNodeMatcher : public NodeMatcher {
|
||||
PrintedNameAndUSR,
|
||||
};
|
||||
|
||||
// Given two sdk nodes, figure out the reason for why they have the same name.
|
||||
// Given two SDK nodes, figure out the reason for why they have the same name.
|
||||
Optional<NameMatchKind> getNameMatchKind(SDKNode *L, SDKNode *R) {
|
||||
if (L->getKind() != R->getKind())
|
||||
return None;
|
||||
@@ -1720,7 +1769,7 @@ class SameNameNodeMatcher : public NodeMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
// Given a list and a priority, find the best matched candidate sdk node.
|
||||
// Given a list and a priority, find the best matched candidate SDK node.
|
||||
SDKNode* findBestNameMatch(ArrayRef<NameMatchCandidate> Candidates,
|
||||
ArrayRef<NameMatchKind> Kinds) {
|
||||
for (auto Kind : Kinds)
|
||||
@@ -1847,6 +1896,16 @@ void detectThrowing(NodePtr L, NodePtr R) {
|
||||
}
|
||||
}
|
||||
|
||||
void detectMutating(NodePtr L, NodePtr R) {
|
||||
assert(L->getKind() == R->getKind());
|
||||
if (auto LF = dyn_cast<SDKNodeAbstractFunc>(L)) {
|
||||
auto RF = R->getAs<SDKNodeAbstractFunc>();
|
||||
if (!LF->isMutating() && RF->isMutating()) {
|
||||
LF->annotate(NodeAnnotation::NowMutating);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void detectRename(NodePtr L, NodePtr R) {
|
||||
assert(L->getKind() == R->getKind());
|
||||
if (isa<SDKNodeDecl>(L) && L->getPrintedName() != R->getPrintedName()) {
|
||||
@@ -1861,7 +1920,7 @@ static void detectRename(NodePtr L, NodePtr R) {
|
||||
// This is first pass on two given SDKNode trees. This pass removes the common part
|
||||
// of two versions of SDK, leaving only the changed part.
|
||||
class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass {
|
||||
static void removeCommomChildren(NodePtr Left, NodePtr Right) {
|
||||
static void removeCommonChildren(NodePtr Left, NodePtr Right) {
|
||||
llvm::SmallPtrSet<NodePtr, 16> LeftToRemove;
|
||||
llvm::SmallPtrSet<NodePtr, 16> RightToRemove;
|
||||
for (auto &LC : Left->getChildren()) {
|
||||
@@ -1902,6 +1961,7 @@ public:
|
||||
SDKNodeKind Kind = Left->getKind();
|
||||
assert(Left->getKind() != SDKNodeKind::Nil &&
|
||||
Right->getKind() != SDKNodeKind::Nil);
|
||||
assert(Kind == SDKNodeKind::Root || *Left != *Right);
|
||||
|
||||
Left->annotate(NodeAnnotation::Updated);
|
||||
Right->annotate(NodeAnnotation::Updated);
|
||||
@@ -1909,6 +1969,7 @@ public:
|
||||
UpdateMap->foundMatch(Left, Right);
|
||||
detectRename(Left, Right);
|
||||
detectThrowing(Left, Right);
|
||||
detectMutating(Left, Right);
|
||||
|
||||
switch(Kind) {
|
||||
case SDKNodeKind::Root:
|
||||
@@ -1916,7 +1977,7 @@ public:
|
||||
// If the matched nodes are both modules, remove the contained
|
||||
// type decls that are identical. If the matched nodes are both type decls,
|
||||
// remove the contained function decls that are identical.
|
||||
removeCommomChildren(Left, Right);
|
||||
removeCommonChildren(Left, Right);
|
||||
NodeVector LeftChildren;
|
||||
NodeVector RightChildren;
|
||||
Left->collectChildren(LeftChildren);
|
||||
@@ -1932,7 +1993,7 @@ public:
|
||||
case SDKNodeKind::TypeAlias:
|
||||
case SDKNodeKind::TypeFunc:
|
||||
case SDKNodeKind::TypeNominal: {
|
||||
// If mactched nodes are both function/var/TypeAlias decls, mapping their
|
||||
// If matched nodes are both function/var/TypeAlias decls, mapping their
|
||||
// parameters sequentially.
|
||||
SequentialNodeMatcher(Left->getChildren(),
|
||||
Right->getChildren(), *this).match();
|
||||
@@ -2054,8 +2115,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<NodePairVector> RenamedNodes;
|
||||
|
||||
// Given a condition, search whether a node satisfies that condition exists
|
||||
// in a tree.
|
||||
class SearchVisitor : public SDKNodeVisitor {
|
||||
@@ -2190,12 +2249,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// DiffItem describes how an element in sdk evolves in a way that migrator can
|
||||
// read conveniently. Each DiffItem corresponds to one json element and contains
|
||||
// DiffItem describes how an element in SDK evolves in a way that migrator can
|
||||
// read conveniently. Each DiffItem corresponds to one JSON element and contains
|
||||
// sub fields explaining how migrator can assist client code to cope with such
|
||||
// sdk change. For instance, the following first json element describes an unwrap
|
||||
// SDK change. For instance, the following first JSON element describes an unwrap
|
||||
// optional change in the first parameter of function "c:@F@CTTextTabGetOptions".
|
||||
// Similarly, the second json element describes a type parameter down cast in the
|
||||
// Similarly, the second JSON element describes a type parameter down cast in the
|
||||
// second parameter of function "c:objc(cs)NSXMLDocument(im)insertChildren:atIndex:".
|
||||
// We keep both usrs because in the future this may support auto-rename.
|
||||
class DiffItem {
|
||||
@@ -2619,6 +2678,17 @@ class DiagnosisEmitter : public SDKNodeVisitor {
|
||||
static void theme(raw_ostream &OS) { OS << "Renamed Decls"; };
|
||||
};
|
||||
|
||||
struct DeclAttrDiag {
|
||||
DeclKind Kind;
|
||||
StringRef DeclName;
|
||||
StringRef AttrName;
|
||||
DeclAttrDiag(DeclKind Kind, StringRef DeclName, StringRef AttrName) :
|
||||
Kind(Kind), DeclName(DeclName), AttrName(AttrName) {}
|
||||
bool operator<(DeclAttrDiag Other) const;
|
||||
void output() const;
|
||||
static void theme(raw_ostream &OS) { OS << "Decl Attribute changes"; };
|
||||
};
|
||||
|
||||
struct DeclTypeChangeDiag {
|
||||
DeclKind Kind;
|
||||
StringRef DeclName;
|
||||
@@ -2636,6 +2706,7 @@ class DiagnosisEmitter : public SDKNodeVisitor {
|
||||
};
|
||||
|
||||
std::set<SDKNodeDecl*> AddedDecls;
|
||||
DiagBag<DeclAttrDiag> AttrChangedDecls;
|
||||
DiagBag<DeclTypeChangeDiag> TypeChangedDecls;
|
||||
DiagBag<RenamedDeclDiag> RenamedDecls;
|
||||
DiagBag<MovedDeclDiag> MovedDecls;
|
||||
@@ -2734,6 +2805,18 @@ void DiagnosisEmitter::DeclTypeChangeDiag::output() const {
|
||||
<< printName(TypeNameAfter) << "\n";
|
||||
}
|
||||
|
||||
|
||||
bool DiagnosisEmitter::DeclAttrDiag::operator<(DeclAttrDiag Other) const {
|
||||
if (Kind != Other.Kind)
|
||||
return Kind < Other.Kind;
|
||||
return DeclName.compare_lower(Other.DeclName);
|
||||
}
|
||||
|
||||
void DiagnosisEmitter::DeclAttrDiag::output() const {
|
||||
llvm::outs() << Kind << "" << printName(DeclName) << " is now " <<
|
||||
printDiagKeyword(AttrName) << "\n";
|
||||
}
|
||||
|
||||
void DiagnosisEmitter::diagnosis(NodePtr LeftRoot, NodePtr RightRoot,
|
||||
UpdatedNodesMap &UpdateMap) {
|
||||
DiagnosisEmitter Emitter(UpdateMap);
|
||||
@@ -2763,6 +2846,16 @@ void DiagnosisEmitter::visitDecl(SDKNodeDecl *Node) {
|
||||
Node->getFullyQualifiedName(),
|
||||
Count->getFullyQualifiedName());
|
||||
}
|
||||
if (Node->isAnnotatedAs(NodeAnnotation::NowMutating)) {
|
||||
AttrChangedDecls.Diags.emplace_back(Node->getDeclKind(),
|
||||
Node->getFullyQualifiedName(),
|
||||
InsertToBuffer("mutating"));
|
||||
}
|
||||
if (Node->isAnnotatedAs(NodeAnnotation::NowThrowing)) {
|
||||
AttrChangedDecls.Diags.emplace_back(Node->getDeclKind(),
|
||||
Node->getFullyQualifiedName(),
|
||||
InsertToBuffer("throwing"));
|
||||
}
|
||||
}
|
||||
void DiagnosisEmitter::visitType(SDKNodeType *Node) {
|
||||
auto *Parent = Node->getParent()->getAs<SDKNodeDecl>();
|
||||
@@ -3302,6 +3395,11 @@ static int prepareForDump(const char *Main,
|
||||
InitInvok.setRuntimeResourcePath(options::ResourceDir);
|
||||
}
|
||||
InitInvok.setFrameworkSearchPaths(options::FrameworkPaths);
|
||||
InitInvok.setImportSearchPaths(options::ModuleInputPaths);
|
||||
for (auto CCFrameworkPath : options::CCSystemFrameworkPaths) {
|
||||
InitInvok.getClangImporterOptions().ExtraArgs.push_back("-iframework");
|
||||
InitInvok.getClangImporterOptions().ExtraArgs.push_back(CCFrameworkPath);
|
||||
}
|
||||
|
||||
if (!options::ModuleList.empty()) {
|
||||
if (readFileLineByLine(options::ModuleList, Modules))
|
||||
@@ -3313,13 +3411,13 @@ static int prepareForDump(const char *Main,
|
||||
}
|
||||
|
||||
if (Modules.empty()) {
|
||||
llvm::errs() << "Need to specifiy -include-all or -module <name>\n";
|
||||
llvm::errs() << "Need to specify -include-all or -module <name>\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void readIgnoredUsrs(llvm::StringSet<> &IgoredUsrs) {
|
||||
static void readIgnoredUsrs(llvm::StringSet<> &IgnoredUsrs) {
|
||||
StringRef Path = options::IgnoreRemovedDeclUSRs;
|
||||
if (Path.empty())
|
||||
return;
|
||||
@@ -3327,7 +3425,7 @@ static void readIgnoredUsrs(llvm::StringSet<> &IgoredUsrs) {
|
||||
llvm::errs() << Path << " does not exist.\n";
|
||||
return;
|
||||
}
|
||||
readFileLineByLine(Path, IgoredUsrs);
|
||||
readFileLineByLine(Path, IgnoredUsrs);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
Reference in New Issue
Block a user