swift-api-digester: add specific logic to detect optional dictionary's key changes.

We've also seen type changes in the frameworks from "[String: Any]?" to
"[StringRepresentable: Any]?". This patch adds specific logic and
attribute for this kind of change on the top of nonnull dictionary
changes.
This commit is contained in:
Xi Ge
2018-04-06 16:41:57 -07:00
parent 924767d0ed
commit cd87f4142d
7 changed files with 88 additions and 13 deletions

View File

@@ -75,6 +75,7 @@ NODE_ANNOTATION(NowMutating)
NODE_ANNOTATION(StaticChange)
NODE_ANNOTATION(OwnershipChange)
NODE_ANNOTATION(DictionaryKeyUpdate)
NODE_ANNOTATION(OptionalDictionaryKeyUpdate)
DECL_ATTR(deprecated)
DECL_ATTR(fixedLayout)

View File

@@ -20,4 +20,5 @@ extern int ANTGlobalValue;
@interface AnimalStatusDescriptor
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingAttributes:(nonnull NSDictionary<NSString*, id> *)attributes;
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingOptionalAttributes:(nullable NSDictionary<NSString*, id> *)attributes;
@end

View File

@@ -20,4 +20,5 @@ typedef NSString * AnimalAttributeName NS_STRING_ENUM;
@interface AnimalStatusDescriptor
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingAttributes:(nonnull NSDictionary<AnimalAttributeName, id> *)attributes;
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingOptionalAttributes:(nullable NSDictionary<AnimalAttributeName, id> *)attributes;
@end

View File

@@ -10,5 +10,6 @@ APINotesTest(APINotesTest.h): TypeAlias AnimalAttributeName(NSString) is now Str
/* Type Changes */
APINotesTest(APINotesTest.h): Func AnimalStatusDescriptor.addingAttributes(_:) has parameter 0 type change from [String : Any] to [AnimalAttributeName : Any]
APINotesTest(APINotesTest.h): Func AnimalStatusDescriptor.addingOptionalAttributes(_:) has parameter 0 type change from [String : Any]? to [AnimalAttributeName : Any]?
/* Decl Attribute changes */

View File

@@ -14,5 +14,6 @@ APINotesTest(APINotesTest.h): Var OldType.oldMember has been renamed to Var NewT
/* Type Changes */
APINotesTest(APINotesTest.h): Func AnimalStatusDescriptor.addingAttributes(_:) has parameter 0 type change from [String : Any] to [AnimalAttributeName : Any]
APINotesTest(APINotesTest.h): Func AnimalStatusDescriptor.addingOptionalAttributes(_:) has parameter 0 type change from [String : Any]? to [AnimalAttributeName : Any]?
/* Decl Attribute changes */

View File

@@ -43,6 +43,50 @@
"RightComment": "AnimalAttributeName",
"ModuleName": "APINotesTest"
},
{
"DiffItemKind": "CommonDiffItem",
"NodeKind": "Function",
"NodeAnnotation": "TypeRewritten",
"ChildIndex": "1:0:0",
"LeftUsr": "c:objc(cs)AnimalStatusDescriptor(im)animalStatusDescriptorByAddingOptionalAttributes:",
"LeftComment": "String",
"RightUsr": "",
"RightComment": "AnimalAttributeName",
"ModuleName": "APINotesTest"
},
{
"DiffItemKind": "CommonDiffItem",
"NodeKind": "Function",
"NodeAnnotation": "OptionalDictionaryKeyUpdate",
"ChildIndex": "1",
"LeftUsr": "c:objc(cs)AnimalStatusDescriptor(im)animalStatusDescriptorByAddingOptionalAttributes:",
"LeftComment": "",
"RightUsr": "",
"RightComment": "AnimalAttributeName",
"ModuleName": "APINotesTest"
},
{
"DiffItemKind": "CommonDiffItem",
"NodeKind": "Function",
"NodeAnnotation": "TypeRewritten",
"ChildIndex": "1:0:0",
"LeftUsr": "c:objc(cs)AnimalStatusDescriptor(im)animalStatusDescriptorByAddingOptionalAttributes:",
"LeftComment": "String",
"RightUsr": "",
"RightComment": "AnimalAttributeName",
"ModuleName": "APINotesTest"
},
{
"DiffItemKind": "CommonDiffItem",
"NodeKind": "Function",
"NodeAnnotation": "OptionalDictionaryKeyUpdate",
"ChildIndex": "1",
"LeftUsr": "c:objc(cs)AnimalStatusDescriptor(im)animalStatusDescriptorByAddingOptionalAttributes:",
"LeftComment": "",
"RightUsr": "",
"RightComment": "AnimalAttributeName",
"ModuleName": "APINotesTest"
},
{
"DiffItemKind": "CommonDiffItem",
"NodeKind": "Function",

View File

@@ -409,7 +409,7 @@ public:
ArrayRef<SDKNode*> getChildren() const;
bool hasSameChildren(const SDKNode &Other) const;
unsigned getChildIndex(NodePtr Child) const;
const SDKNode* getOnlyChild() const;
SDKNode* getOnlyChild() const;
SDKContext &getSDKContext() const { return Ctx; }
SDKNodeRoot *getRootNode() const;
template <typename T> const T *getAs() const;
@@ -575,7 +575,7 @@ unsigned SDKNode::getChildIndex(NodePtr Child) const {
return std::find(Children.begin(), Children.end(), Child) - Children.begin();
}
const SDKNode* SDKNode::getOnlyChild() const {
SDKNode* SDKNode::getOnlyChild() const {
assert(Children.size() == 1 && "more that one child.");
return *Children.begin();
}
@@ -2693,12 +2693,11 @@ class ChangeRefinementPass : public SDKTreeDiffPass, public SDKNodeVisitor {
return false;
}
bool detectDictionaryKeyChange(SDKNodeType *L, SDKNodeType *R) {
if (!IsVisitingLeft)
return false;
static StringRef detectDictionaryKeyChangeInternal(SDKNodeType *L,
SDKNodeType *R) {
if (L->getTypeKind() != KnownTypeKind::Dictionary ||
R->getTypeKind() != KnownTypeKind::Dictionary)
return false;
return StringRef();
auto *Left = dyn_cast<SDKNodeTypeNominal>(L);
auto *Right = dyn_cast<SDKNodeTypeNominal>(R);
assert(Left && Right);
@@ -2707,20 +2706,45 @@ class ChangeRefinementPass : public SDKTreeDiffPass, public SDKNodeVisitor {
auto* LKey = dyn_cast<SDKNodeTypeNominal>(*Left->getChildBegin());
auto* RKey = dyn_cast<SDKNodeTypeNominal>(*Right->getChildBegin());
if (!LKey || !RKey)
return false;
return StringRef();
if (LKey->getTypeKind() != KnownTypeKind::String)
return false;
return StringRef();
auto Results = RKey->getRootNode()->getDescendantsByUsr(RKey->getUsr());
if (Results.empty())
return false;
return StringRef();
if (auto DT = dyn_cast<SDKNodeDeclType>(Results.front())) {
if (DT->isConformingTo(KnownProtocolKind::RawRepresentable)) {
L->annotate(NodeAnnotation::DictionaryKeyUpdate);
L->annotate(NodeAnnotation::TypeRewrittenRight,
DT->getFullyQualifiedName());
return true;
return DT->getFullyQualifiedName();
}
}
return StringRef();
}
bool detectDictionaryKeyChange(SDKNodeType *L, SDKNodeType *R) {
if (!IsVisitingLeft)
return false;
// We only care if this the top-level type node.
if (!isa<SDKNodeDecl>(L->getParent()) || !isa<SDKNodeDecl>(R->getParent()))
return false;
StringRef KeyChangedTo;
if (L->getTypeKind() == KnownTypeKind::Optional &&
R->getTypeKind() == KnownTypeKind::Optional) {
// Detect [String: Any]? to [StringRepresentableStruct: Any]? Chnage
KeyChangedTo =
detectDictionaryKeyChangeInternal(L->getOnlyChild()->getAs<SDKNodeType>(),
R->getOnlyChild()->getAs<SDKNodeType>());
} else {
// Detect [String: Any] to [StringRepresentableStruct: Any] Chnage
KeyChangedTo = detectDictionaryKeyChangeInternal(L, R);
}
if (!KeyChangedTo.empty()) {
L->annotate(L->getTypeKind() == KnownTypeKind::Optional ?
NodeAnnotation::OptionalDictionaryKeyUpdate :
NodeAnnotation::DictionaryKeyUpdate);
L->annotate(NodeAnnotation::TypeRewrittenRight, KeyChangedTo);
return true;
}
return false;
}
@@ -2864,6 +2888,7 @@ class DiffItemEmitter : public SDKNodeVisitor {
static StringRef getRightComment(NodePtr Node, NodeAnnotation Anno) {
switch (Anno) {
case NodeAnnotation::DictionaryKeyUpdate:
case NodeAnnotation::OptionalDictionaryKeyUpdate:
case NodeAnnotation::TypeRewritten:
return Node->getAnnotateComment(NodeAnnotation::TypeRewrittenRight);
case NodeAnnotation::ModernizeEnum:
@@ -2922,6 +2947,7 @@ class DiffItemEmitter : public SDKNodeVisitor {
NodeAnnotation::Rename,
NodeAnnotation::NowThrowing,
NodeAnnotation::DictionaryKeyUpdate,
NodeAnnotation::OptionalDictionaryKeyUpdate,
});
}