Skip to content

Commit 536c232

Browse files
authored
Merge pull request #15524 from nkcsgexi/api-digester-raw
swift-api-digester: teach the tool to detect [String:Any] changes to [StringRepresentable:Any].
2 parents 3d7646a + 784116a commit 536c232

File tree

3 files changed

+100
-25
lines changed

3 files changed

+100
-25
lines changed

include/swift/IDE/DigesterEnums.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#define KNOWN_TYPE(NAME)
1919
#endif
2020

21+
#ifndef KNOWN_PROTOCOL
22+
#define KNOWN_PROTOCOL(NAME)
23+
#endif
24+
2125
#ifndef DIFF_ITEM_KIND
2226
#define DIFF_ITEM_KIND(NAME)
2327
#endif
@@ -70,6 +74,7 @@ NODE_ANNOTATION(NowThrowing)
7074
NODE_ANNOTATION(NowMutating)
7175
NODE_ANNOTATION(StaticChange)
7276
NODE_ANNOTATION(OwnershipChange)
77+
NODE_ANNOTATION(DictionaryKeyUpdate)
7378

7479
DECL_ATTR(deprecated)
7580
DECL_ATTR(fixedLayout)
@@ -100,6 +105,10 @@ KNOWN_TYPE(ImplicitlyUnwrappedOptional)
100105
KNOWN_TYPE(Void)
101106
KNOWN_TYPE(Unmanaged)
102107
KNOWN_TYPE(Function)
108+
KNOWN_TYPE(Dictionary)
109+
KNOWN_TYPE(String)
110+
111+
KNOWN_PROTOCOL(RawRepresentable)
103112

104113
DIFF_ITEM_KIND(CommonDiffItem)
105114
DIFF_ITEM_KIND(TypeMemberDiffItem)
@@ -149,6 +158,7 @@ SPECIAL_CASE_ID(ToUIntMax)
149158
#undef DIFF_ITEM_KEY_KIND
150159
#undef DIFF_ITEM_KIND
151160
#undef KNOWN_TYPE
161+
#undef KNOWN_PROTOCOL
152162
#undef KEY
153163
#undef DECL_ATTR
154164
#undef NODE_ANNOTATION

test/api-digester/Outputs/apinotes-migrator-gen.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
"RightComment": "AnimalAttributeName",
1111
"ModuleName": "APINotesTest"
1212
},
13+
{
14+
"DiffItemKind": "CommonDiffItem",
15+
"NodeKind": "Function",
16+
"NodeAnnotation": "DictionaryKeyUpdate",
17+
"ChildIndex": "1",
18+
"LeftUsr": "c:objc(cs)AnimalStatusDescriptor(im)animalStatusDescriptorByAddingAttributes:",
19+
"LeftComment": "",
20+
"RightUsr": "",
21+
"RightComment": "AnimalAttributeName",
22+
"ModuleName": "APINotesTest"
23+
},
1324
{
1425
"DiffItemKind": "CommonDiffItem",
1526
"NodeKind": "Function",
@@ -21,6 +32,17 @@
2132
"RightComment": "AnimalAttributeName",
2233
"ModuleName": "APINotesTest"
2334
},
35+
{
36+
"DiffItemKind": "CommonDiffItem",
37+
"NodeKind": "Function",
38+
"NodeAnnotation": "DictionaryKeyUpdate",
39+
"ChildIndex": "1",
40+
"LeftUsr": "c:objc(cs)AnimalStatusDescriptor(im)animalStatusDescriptorByAddingAttributes:",
41+
"LeftComment": "",
42+
"RightUsr": "",
43+
"RightComment": "AnimalAttributeName",
44+
"ModuleName": "APINotesTest"
45+
},
2446
{
2547
"DiffItemKind": "CommonDiffItem",
2648
"NodeKind": "Function",

tools/swift-api-digester/swift-api-digester.cpp

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ enum class KnownTypeKind: uint8_t {
277277
Unknown,
278278
};
279279

280+
enum class KnownProtocolKind: uint8_t {
281+
#define KNOWN_PROTOCOL(NAME) NAME,
282+
#include "swift/IDE/DigesterEnums.def"
283+
};
284+
280285
enum class SDKDeclAttrKind: uint8_t {
281286
#define DECL_ATTR(Name) DAK_##Name,
282287
#include "swift/IDE/DigesterEnums.def"
@@ -378,11 +383,11 @@ class SDKNode {
378383
void removeChild(ChildIt CI) { Children.erase(CI); }
379384
ChildIt getChildBegin() { return Children.begin(); }
380385
void annotate(NodeAnnotation Anno) { Annotations.insert(Anno); }
386+
void annotate(NodeAnnotation Anno, StringRef Comment);
381387
NodePtr getParent() const { return Parent; };
382388
unsigned getChildrenCount() const { return Children.size(); }
383389
NodePtr childAt(unsigned I) const;
384390
void removeChild(NodePtr C);
385-
void addAnnotateComment(NodeAnnotation Anno, StringRef Comment);
386391
StringRef getAnnotateComment(NodeAnnotation Anno) const;
387392
bool isAnnotatedAs(NodeAnnotation Anno) const;
388393
void addChild(SDKNode *Child);
@@ -598,8 +603,9 @@ void SDKNode::removeChild(NodePtr C) {
598603
Children.erase(std::find(Children.begin(), Children.end(), C));
599604
}
600605

601-
void SDKNode::addAnnotateComment(NodeAnnotation Anno, StringRef Comment) {
602-
assert(isAnnotatedAs(Anno) && "Cannot find annotation");
606+
void SDKNode::annotate(NodeAnnotation Anno, StringRef Comment) {
607+
assert(!isAnnotatedAs(Anno) && "already annotated");
608+
annotate(Anno);
603609
AnnotateComments[Anno] = Comment;
604610
}
605611

@@ -831,6 +837,18 @@ class SDKNodeTypeDecl : public SDKNodeDecl {
831837
}
832838
return None;
833839
}
840+
841+
bool isConformingTo(KnownProtocolKind Kind) const {
842+
StringRef Usr;
843+
switch (Kind) {
844+
#define KNOWN_PROTOCOL(NAME) \
845+
case KnownProtocolKind::NAME: \
846+
return std::find(ConformingProtocols.begin(), \
847+
ConformingProtocols.end(), \
848+
#NAME) != ConformingProtocols.end();
849+
#include "swift/IDE/DigesterEnums.def"
850+
}
851+
}
834852
};
835853

836854
class SDKNodeTypeAlias : public SDKNodeDecl {
@@ -1957,8 +1975,7 @@ class RemovedAddedNodeMatcher : public NodeMatcher, public MatchedNodeListener {
19571975
} else {
19581976
return false;
19591977
}
1960-
R->annotate(NodeAnnotation::PropertyName);
1961-
R->addAnnotateComment(NodeAnnotation::PropertyName, A->getPrintedName());
1978+
R->annotate(NodeAnnotation::PropertyName, A->getPrintedName());
19621979
foundMatch(R, A);
19631980
return true;
19641981
}
@@ -1995,11 +2012,10 @@ class RemovedAddedNodeMatcher : public NodeMatcher, public MatchedNodeListener {
19952012
if (auto VC = dyn_cast<SDKNodeVar>(Child)) {
19962013
auto LastPartOfA = getLastPartOfUsr(VC);
19972014
if (LastPartOfA && LastPartOfR.getValue() == LastPartOfA.getValue()) {
1998-
R->annotate(NodeAnnotation::ModernizeEnum);
19992015
std::string FullName = (llvm::Twine(A->getName()) + "." +
20002016
Child->getName()).str();
2001-
R->addAnnotateComment(NodeAnnotation::ModernizeEnum,
2002-
R->getSDKContext().buffer(FullName));
2017+
R->annotate(NodeAnnotation::ModernizeEnum,
2018+
R->getSDKContext().buffer(FullName));
20032019
foundMatch(R, A);
20042020
return true;
20052021
}
@@ -2304,10 +2320,8 @@ static void detectRename(NodePtr L, NodePtr R) {
23042320
assert(L->getKind() == R->getKind());
23052321
if (isa<SDKNodeDecl>(L) && L->getPrintedName() != R->getPrintedName()) {
23062322
L->annotate(NodeAnnotation::Rename);
2307-
L->annotate(NodeAnnotation::RenameOldName);
2308-
L->addAnnotateComment(NodeAnnotation::RenameOldName, L->getPrintedName());
2309-
L->annotate(NodeAnnotation::RenameNewName);
2310-
L->addAnnotateComment(NodeAnnotation::RenameNewName, R->getPrintedName());
2323+
L->annotate(NodeAnnotation::RenameOldName, L->getPrintedName());
2324+
L->annotate(NodeAnnotation::RenameNewName, R->getPrintedName());
23112325
}
23122326
}
23132327

@@ -2477,12 +2491,10 @@ class TypeMemberDiffFinder : public SDKNodeVisitor {
24772491
diffNode->getKind() == SDKNodeKind::Function &&
24782492
node->isNameValid()) {
24792493
diffNode->annotate(NodeAnnotation::Rename);
2480-
diffNode->annotate(NodeAnnotation::RenameOldName);
2481-
diffNode->addAnnotateComment(NodeAnnotation::RenameOldName,
2482-
diffNode->getPrintedName());
2483-
diffNode->annotate(NodeAnnotation::RenameNewName);
2484-
diffNode->addAnnotateComment(NodeAnnotation::RenameNewName,
2485-
node->getParent()->getPrintedName());
2494+
diffNode->annotate(NodeAnnotation::RenameOldName,
2495+
diffNode->getPrintedName());
2496+
diffNode->annotate(NodeAnnotation::RenameNewName,
2497+
node->getParent()->getPrintedName());
24862498
}
24872499
}
24882500

@@ -2587,17 +2599,45 @@ class ChangeRefinementPass : public SDKTreeDiffPass, public SDKNodeVisitor {
25872599
(Node->getName() != Counter->getName()||
25882600
Node->getChildrenCount() != Counter->getChildrenCount())) {
25892601
Node->annotate(NodeAnnotation::TypeRewritten);
2590-
Node->annotate(NodeAnnotation::TypeRewrittenLeft);
2591-
Node->annotate(NodeAnnotation::TypeRewrittenRight);
2592-
Node->addAnnotateComment(NodeAnnotation::TypeRewrittenLeft,
2593-
Node->getPrintedName());
2594-
Node->addAnnotateComment(NodeAnnotation::TypeRewrittenRight,
2595-
Counter->getPrintedName());
2602+
Node->annotate(NodeAnnotation::TypeRewrittenLeft, Node->getPrintedName());
2603+
Node->annotate(NodeAnnotation::TypeRewrittenRight,
2604+
Counter->getPrintedName());
25962605
return true;
25972606
}
25982607
return false;
25992608
}
26002609

2610+
bool detectDictionaryKeyChange(SDKNodeType *L, SDKNodeType *R) {
2611+
if (!IsVisitingLeft)
2612+
return false;
2613+
if (L->getTypeKind() != KnownTypeKind::Dictionary ||
2614+
R->getTypeKind() != KnownTypeKind::Dictionary)
2615+
return false;
2616+
auto *Left = dyn_cast<SDKNodeTypeNominal>(L);
2617+
auto *Right = dyn_cast<SDKNodeTypeNominal>(R);
2618+
assert(Left && Right);
2619+
assert(Left->getChildrenCount() == 2);
2620+
assert(Right->getChildrenCount() == 2);
2621+
auto* LKey = dyn_cast<SDKNodeTypeNominal>(*Left->getChildBegin());
2622+
auto* RKey = dyn_cast<SDKNodeTypeNominal>(*Right->getChildBegin());
2623+
if (!LKey || !RKey)
2624+
return false;
2625+
if (LKey->getTypeKind() != KnownTypeKind::String)
2626+
return false;
2627+
auto Results = RKey->getRootNode()->getDescendantsByUsr(RKey->getUsr());
2628+
if (Results.empty())
2629+
return false;
2630+
if (auto DT = dyn_cast<SDKNodeTypeDecl>(Results.front())) {
2631+
if (DT->isConformingTo(KnownProtocolKind::RawRepresentable)) {
2632+
L->annotate(NodeAnnotation::DictionaryKeyUpdate);
2633+
L->annotate(NodeAnnotation::TypeRewrittenRight,
2634+
DT->getFullyQualifiedName());
2635+
return true;
2636+
}
2637+
}
2638+
return false;
2639+
}
2640+
26012641
bool isUnhandledCase(SDKNodeType *Node) {
26022642
auto Counter = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeType>();
26032643
return Node->getTypeKind() == KnownTypeKind::Void ||
@@ -2628,6 +2668,7 @@ class ChangeRefinementPass : public SDKTreeDiffPass, public SDKNodeVisitor {
26282668
detectOptionalUpdate(Node, Counter)||
26292669
detectWrapImplicitOptional(Node, Counter)||
26302670
detectUnmanagedUpdate(Node, Counter)||
2671+
detectDictionaryKeyChange(Node, Counter) ||
26312672
detectTypeRewritten(Node, Counter);
26322673
(void) Result;
26332674
return;
@@ -2739,6 +2780,7 @@ class DiffItemEmitter : public SDKNodeVisitor {
27392780

27402781
static StringRef getRightComment(NodePtr Node, NodeAnnotation Anno) {
27412782
switch (Anno) {
2783+
case NodeAnnotation::DictionaryKeyUpdate:
27422784
case NodeAnnotation::TypeRewritten:
27432785
return Node->getAnnotateComment(NodeAnnotation::TypeRewrittenRight);
27442786
case NodeAnnotation::ModernizeEnum:
@@ -2795,7 +2837,8 @@ class DiffItemEmitter : public SDKNodeVisitor {
27952837
NodeAnnotation::GetterToProperty,
27962838
NodeAnnotation::ModernizeEnum,
27972839
NodeAnnotation::Rename,
2798-
NodeAnnotation::NowThrowing
2840+
NodeAnnotation::NowThrowing,
2841+
NodeAnnotation::DictionaryKeyUpdate,
27992842
});
28002843
}
28012844

0 commit comments

Comments
 (0)