api-digester: teach the tool to detect new mutating/throwing functions (#5284)

This commit is contained in:
Xi Ge
2016-10-13 21:04:39 -07:00
committed by GitHub
parent 6f19ad7356
commit edea59722e
7 changed files with 362 additions and 34 deletions

View File

@@ -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"
@@ -361,7 +362,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) {
@@ -465,27 +465,6 @@ 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;
@@ -651,17 +630,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,
@@ -840,6 +808,49 @@ NodeUniquePtr SDKNode::constructSDKNode(llvm::yaml::MappingNode *Node) {
return Result;
}
bool SDKNode::operator==(const SDKNode &Other) const {
if (getKind() != Other.getKind())
return false;
switch(getKind()) {
case SDKNodeKind::TypeNominal:
case SDKNodeKind::TypeFunc: {
auto Left = this->getAs<SDKNodeType>();
auto Right = (&Other)->getAs<SDKNodeType>();
return 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 false;
if (Left->isThrowing() ^ Right->isThrowing())
return 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 false;
}
return true;
}
return false;
}
}
}
// The pretty printer of a tree of SDKNode
class SDKNodeDumpVisitor : public SDKNodeVisitor {
void dumpSpace(int Num) {
@@ -1867,6 +1878,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()) {
@@ -1922,6 +1943,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);
@@ -1929,6 +1951,7 @@ public:
UpdateMap->foundMatch(Left, Right);
detectRename(Left, Right);
detectThrowing(Left, Right);
detectMutating(Left, Right);
switch(Kind) {
case SDKNodeKind::Root:
@@ -2639,6 +2662,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;
@@ -2656,6 +2690,7 @@ class DiagnosisEmitter : public SDKNodeVisitor {
};
std::set<SDKNodeDecl*> AddedDecls;
DiagBag<DeclAttrDiag> AttrChangedDecls;
DiagBag<DeclTypeChangeDiag> TypeChangedDecls;
DiagBag<RenamedDeclDiag> RenamedDecls;
DiagBag<MovedDeclDiag> MovedDecls;
@@ -2754,6 +2789,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);
@@ -2783,6 +2830,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>();