mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -75,6 +75,7 @@ NODE_ANNOTATION(NowMutating)
|
|||||||
NODE_ANNOTATION(StaticChange)
|
NODE_ANNOTATION(StaticChange)
|
||||||
NODE_ANNOTATION(OwnershipChange)
|
NODE_ANNOTATION(OwnershipChange)
|
||||||
NODE_ANNOTATION(DictionaryKeyUpdate)
|
NODE_ANNOTATION(DictionaryKeyUpdate)
|
||||||
|
NODE_ANNOTATION(OptionalDictionaryKeyUpdate)
|
||||||
|
|
||||||
DECL_ATTR(deprecated)
|
DECL_ATTR(deprecated)
|
||||||
DECL_ATTR(fixedLayout)
|
DECL_ATTR(fixedLayout)
|
||||||
|
|||||||
@@ -20,4 +20,5 @@ extern int ANTGlobalValue;
|
|||||||
|
|
||||||
@interface AnimalStatusDescriptor
|
@interface AnimalStatusDescriptor
|
||||||
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingAttributes:(nonnull NSDictionary<NSString*, id> *)attributes;
|
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingAttributes:(nonnull NSDictionary<NSString*, id> *)attributes;
|
||||||
|
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingOptionalAttributes:(nullable NSDictionary<NSString*, id> *)attributes;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -20,4 +20,5 @@ typedef NSString * AnimalAttributeName NS_STRING_ENUM;
|
|||||||
|
|
||||||
@interface AnimalStatusDescriptor
|
@interface AnimalStatusDescriptor
|
||||||
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingAttributes:(nonnull NSDictionary<AnimalAttributeName, id> *)attributes;
|
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingAttributes:(nonnull NSDictionary<AnimalAttributeName, id> *)attributes;
|
||||||
|
- (nonnull AnimalStatusDescriptor *)animalStatusDescriptorByAddingOptionalAttributes:(nullable NSDictionary<AnimalAttributeName, id> *)attributes;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ APINotesTest(APINotesTest.h): TypeAlias AnimalAttributeName(NSString) is now Str
|
|||||||
|
|
||||||
/* Type Changes */
|
/* Type Changes */
|
||||||
APINotesTest(APINotesTest.h): Func AnimalStatusDescriptor.addingAttributes(_:) has parameter 0 type change from [String : Any] to [AnimalAttributeName : Any]
|
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 */
|
/* Decl Attribute changes */
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ APINotesTest(APINotesTest.h): Var OldType.oldMember has been renamed to Var NewT
|
|||||||
|
|
||||||
/* Type Changes */
|
/* Type Changes */
|
||||||
APINotesTest(APINotesTest.h): Func AnimalStatusDescriptor.addingAttributes(_:) has parameter 0 type change from [String : Any] to [AnimalAttributeName : Any]
|
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 */
|
/* Decl Attribute changes */
|
||||||
|
|||||||
@@ -43,6 +43,50 @@
|
|||||||
"RightComment": "AnimalAttributeName",
|
"RightComment": "AnimalAttributeName",
|
||||||
"ModuleName": "APINotesTest"
|
"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",
|
"DiffItemKind": "CommonDiffItem",
|
||||||
"NodeKind": "Function",
|
"NodeKind": "Function",
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ public:
|
|||||||
ArrayRef<SDKNode*> getChildren() const;
|
ArrayRef<SDKNode*> getChildren() const;
|
||||||
bool hasSameChildren(const SDKNode &Other) const;
|
bool hasSameChildren(const SDKNode &Other) const;
|
||||||
unsigned getChildIndex(NodePtr Child) const;
|
unsigned getChildIndex(NodePtr Child) const;
|
||||||
const SDKNode* getOnlyChild() const;
|
SDKNode* getOnlyChild() const;
|
||||||
SDKContext &getSDKContext() const { return Ctx; }
|
SDKContext &getSDKContext() const { return Ctx; }
|
||||||
SDKNodeRoot *getRootNode() const;
|
SDKNodeRoot *getRootNode() const;
|
||||||
template <typename T> const T *getAs() 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();
|
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.");
|
assert(Children.size() == 1 && "more that one child.");
|
||||||
return *Children.begin();
|
return *Children.begin();
|
||||||
}
|
}
|
||||||
@@ -2693,12 +2693,11 @@ class ChangeRefinementPass : public SDKTreeDiffPass, public SDKNodeVisitor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool detectDictionaryKeyChange(SDKNodeType *L, SDKNodeType *R) {
|
static StringRef detectDictionaryKeyChangeInternal(SDKNodeType *L,
|
||||||
if (!IsVisitingLeft)
|
SDKNodeType *R) {
|
||||||
return false;
|
|
||||||
if (L->getTypeKind() != KnownTypeKind::Dictionary ||
|
if (L->getTypeKind() != KnownTypeKind::Dictionary ||
|
||||||
R->getTypeKind() != KnownTypeKind::Dictionary)
|
R->getTypeKind() != KnownTypeKind::Dictionary)
|
||||||
return false;
|
return StringRef();
|
||||||
auto *Left = dyn_cast<SDKNodeTypeNominal>(L);
|
auto *Left = dyn_cast<SDKNodeTypeNominal>(L);
|
||||||
auto *Right = dyn_cast<SDKNodeTypeNominal>(R);
|
auto *Right = dyn_cast<SDKNodeTypeNominal>(R);
|
||||||
assert(Left && Right);
|
assert(Left && Right);
|
||||||
@@ -2707,20 +2706,45 @@ class ChangeRefinementPass : public SDKTreeDiffPass, public SDKNodeVisitor {
|
|||||||
auto* LKey = dyn_cast<SDKNodeTypeNominal>(*Left->getChildBegin());
|
auto* LKey = dyn_cast<SDKNodeTypeNominal>(*Left->getChildBegin());
|
||||||
auto* RKey = dyn_cast<SDKNodeTypeNominal>(*Right->getChildBegin());
|
auto* RKey = dyn_cast<SDKNodeTypeNominal>(*Right->getChildBegin());
|
||||||
if (!LKey || !RKey)
|
if (!LKey || !RKey)
|
||||||
return false;
|
return StringRef();
|
||||||
if (LKey->getTypeKind() != KnownTypeKind::String)
|
if (LKey->getTypeKind() != KnownTypeKind::String)
|
||||||
return false;
|
return StringRef();
|
||||||
auto Results = RKey->getRootNode()->getDescendantsByUsr(RKey->getUsr());
|
auto Results = RKey->getRootNode()->getDescendantsByUsr(RKey->getUsr());
|
||||||
if (Results.empty())
|
if (Results.empty())
|
||||||
return false;
|
return StringRef();
|
||||||
if (auto DT = dyn_cast<SDKNodeDeclType>(Results.front())) {
|
if (auto DT = dyn_cast<SDKNodeDeclType>(Results.front())) {
|
||||||
if (DT->isConformingTo(KnownProtocolKind::RawRepresentable)) {
|
if (DT->isConformingTo(KnownProtocolKind::RawRepresentable)) {
|
||||||
L->annotate(NodeAnnotation::DictionaryKeyUpdate);
|
return DT->getFullyQualifiedName();
|
||||||
L->annotate(NodeAnnotation::TypeRewrittenRight,
|
|
||||||
DT->getFullyQualifiedName());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2864,6 +2888,7 @@ class DiffItemEmitter : public SDKNodeVisitor {
|
|||||||
static StringRef getRightComment(NodePtr Node, NodeAnnotation Anno) {
|
static StringRef getRightComment(NodePtr Node, NodeAnnotation Anno) {
|
||||||
switch (Anno) {
|
switch (Anno) {
|
||||||
case NodeAnnotation::DictionaryKeyUpdate:
|
case NodeAnnotation::DictionaryKeyUpdate:
|
||||||
|
case NodeAnnotation::OptionalDictionaryKeyUpdate:
|
||||||
case NodeAnnotation::TypeRewritten:
|
case NodeAnnotation::TypeRewritten:
|
||||||
return Node->getAnnotateComment(NodeAnnotation::TypeRewrittenRight);
|
return Node->getAnnotateComment(NodeAnnotation::TypeRewrittenRight);
|
||||||
case NodeAnnotation::ModernizeEnum:
|
case NodeAnnotation::ModernizeEnum:
|
||||||
@@ -2922,6 +2947,7 @@ class DiffItemEmitter : public SDKNodeVisitor {
|
|||||||
NodeAnnotation::Rename,
|
NodeAnnotation::Rename,
|
||||||
NodeAnnotation::NowThrowing,
|
NodeAnnotation::NowThrowing,
|
||||||
NodeAnnotation::DictionaryKeyUpdate,
|
NodeAnnotation::DictionaryKeyUpdate,
|
||||||
|
NodeAnnotation::OptionalDictionaryKeyUpdate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user