swift-api-digester: Eliminate false positives introduced by moving a member declaration to super classes.

We shouldn't report these moved declarations as source breaking changes.

rdar://32778228
This commit is contained in:
Xi Ge
2017-06-21 17:46:59 -07:00
parent 87a0cfb910
commit f6e6484437
4 changed files with 85 additions and 9 deletions

View File

@@ -306,6 +306,8 @@ struct SDKNodeInitInfo {
SDKNode* createSDKNode(SDKNodeKind Kind);
};
class SDKNodeRoot;
class SDKNode {
typedef std::vector<SDKNode*>::iterator ChildIt;
SDKContext &Ctx;
@@ -352,6 +354,7 @@ public:
unsigned getChildIndex(NodePtr Child) const;
const SDKNode* getOnlyChild() const;
SDKContext &getSDKContext() const { return Ctx; }
SDKNodeRoot *getRootNode() const;
template <typename T> const T *getAs() const;
template <typename T> T *getAs();
};
@@ -389,6 +392,27 @@ public:
bool isStatic() const { return IsStatic; };
};
class SDKNodeRoot :public SDKNode {
/// This keeps track of all decl descendants with USRs.
llvm::StringMap<SDKNodeDecl*> DescendantDeclTable;
public:
SDKNodeRoot(SDKNodeInitInfo Info) : SDKNode(Info, SDKNodeKind::Root) {}
static SDKNode *getInstance(SDKContext &Ctx);
static bool classof(const SDKNode *N);
void registerDescendant(SDKNode *D) {
if (auto DD = dyn_cast<SDKNodeDecl>(D)) {
assert(!DD->getUsr().empty());
DescendantDeclTable[DD->getUsr()] = DD;
}
}
Optional<SDKNodeDecl*> getDescendantByUsr(StringRef Usr) {
if (DescendantDeclTable.count(Usr))
return DescendantDeclTable[Usr];
return None;
}
};
NodePtr UpdatedNodesMap::findUpdateCounterpart(const SDKNode *Node) const {
assert(Node->isAnnotatedAs(NodeAnnotation::Updated) && "Not update operation.");
auto FoundPair = std::find_if(MapImpl.begin(), MapImpl.end(),
@@ -475,9 +499,27 @@ const SDKNode* SDKNode::getOnlyChild() const {
return *Children.begin();
}
SDKNodeRoot *SDKNode::getRootNode() const {
for (auto *Root = const_cast<SDKNode*>(this); ; Root = Root->getParent()) {
if (auto Result = dyn_cast<SDKNodeRoot>(Root))
return Result;
}
llvm_unreachable("Unhandled SDKNodeKind in switch.");
}
void SDKNode::addChild(SDKNode *Child) {
Child->Parent = this;
Children.push_back(Child);
if (auto *Root = dyn_cast<SDKNodeRoot>(this)) {
struct DeclCollector: public SDKNodeVisitor {
SDKNodeRoot &Root;
DeclCollector(SDKNodeRoot &Root): Root(Root) {}
void visit(NodePtr Node) override {
Root.registerDescendant(Node);
}
} Collector(*Root);
SDKNode::preorderVisit(Child, Collector);
}
}
ArrayRef<SDKNode*> SDKNode::getChildren() const {
@@ -602,13 +644,6 @@ bool SDKNodeType::hasTypeAttribute(TypeAttrKind DAKind) const {
TypeAttributes.end();
}
class SDKNodeRoot : public SDKNode {
public:
SDKNodeRoot(SDKNodeInitInfo Info) : SDKNode(Info, SDKNodeKind::Root) {}
static SDKNode *getInstance(SDKContext &Ctx);
static bool classof(const SDKNode *N);
};
SDKNode *SDKNodeRoot::getInstance(SDKContext &Ctx) {
SDKNodeInitInfo Info(Ctx);
Info.Name = Ctx.buffer("TopLevel");
@@ -690,6 +725,27 @@ public:
SuperclassUsr(Info.SuperclassUsr) {}
static bool classof(const SDKNode *N);
StringRef getSuperClassUsr() const { return SuperclassUsr; }
Optional<SDKNodeTypeDecl*> getSuperclass() const {
if (SuperclassUsr.empty())
return None;
return (*getRootNode()->getDescendantByUsr(SuperclassUsr))->
getAs<SDKNodeTypeDecl>();
}
/// Finding the node through all children, including the inheritted ones,
/// whose printed name matches with the given name.
Optional<SDKNodeDecl*> lookupChildByPrintedName(StringRef Name) const {
for (auto C : getChildren()) {
if (C->getPrintedName() == Name)
return C->getAs<SDKNodeDecl>();
}
// Finding from the inheritance chain.
if (auto Super = getSuperclass()) {
return (*Super)->lookupChildByPrintedName(Name);
}
return None;
}
};
class SDKNodeTypeAlias : public SDKNodeDecl {
@@ -2795,6 +2851,22 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
return;
}
}
// We should exlude those declarations that are pulled up to the super classes.
bool FoundInSuperclass = false;
if (auto PD = dyn_cast<SDKNodeDecl>(Node->getParent())) {
if (PD->isAnnotatedAs(NodeAnnotation::Updated)) {
// Get the updated counterpart of the parent decl.
if (auto RTD = dyn_cast<SDKNodeTypeDecl>(UpdateMap.
findUpdateCounterpart(PD))) {
// Look up by the printed name in the counterpart.
FoundInSuperclass =
RTD->lookupChildByPrintedName(Node->getPrintedName()).hasValue();
}
}
}
if (FoundInSuperclass)
return;
RemovedDecls.Diags.emplace_back(Node->getDeclKind(),
Node->getFullyQualifiedName(),
Node->isDeprecated());