@@ -179,6 +179,7 @@ bool contains(ArrayRef<T> container, T instance) {
179
179
class SDKNode ;
180
180
typedef SDKNode* NodePtr;
181
181
typedef std::map<NodePtr, NodePtr> ParentMap;
182
+ typedef std::map<NodePtr, NodePtr> NodeMap;
182
183
typedef std::vector<NodePtr> NodeVector;
183
184
184
185
// The interface used to visit the SDK tree.
@@ -231,6 +232,7 @@ class SDKContext {
231
232
llvm::StringSet<> TextData;
232
233
llvm::BumpPtrAllocator Allocator;
233
234
UpdatedNodesMap UpdateMap;
235
+ NodeMap TypeAliasUpdateMap;
234
236
235
237
public:
236
238
llvm::BumpPtrAllocator &allocator () {
@@ -242,6 +244,10 @@ class SDKContext {
242
244
UpdatedNodesMap &getNodeUpdateMap () {
243
245
return UpdateMap;
244
246
}
247
+ NodeMap &getTypeAliasUpdateMap () {
248
+ return TypeAliasUpdateMap;
249
+ }
250
+
245
251
};
246
252
247
253
// A node matcher will traverse two trees of SDKNode and find matched nodes
@@ -838,6 +844,15 @@ class SDKNodeTypeDecl : public SDKNodeDecl {
838
844
return None;
839
845
}
840
846
847
+ SDKNodeType *getRawValueType () const {
848
+ if (isConformingTo (KnownProtocolKind::RawRepresentable)) {
849
+ if (auto RV = lookupChildByPrintedName (" rawValue" )) {
850
+ return (*(*RV)->getChildBegin ())->getAs <SDKNodeType>();
851
+ }
852
+ }
853
+ return nullptr ;
854
+ }
855
+
841
856
bool isConformingTo (KnownProtocolKind Kind) const {
842
857
StringRef Usr;
843
858
switch (Kind) {
@@ -855,6 +870,9 @@ class SDKNodeTypeAlias : public SDKNodeDecl {
855
870
public:
856
871
SDKNodeTypeAlias (SDKNodeInitInfo Info) : SDKNodeDecl(Info,
857
872
SDKNodeKind::TypeAlias) {}
873
+ const SDKNodeType* getUnderlyingType () const {
874
+ return getOnlyChild ()->getAs <SDKNodeType>();
875
+ }
858
876
static bool classof (const SDKNode *N);
859
877
};
860
878
@@ -1592,8 +1610,8 @@ class SwiftDeclCollector : public VisibleDeclConsumer {
1592
1610
1593
1611
// After collecting decls, either from imported modules or from a previously
1594
1612
// serialized JSON file, using this function to get the root of the SDK.
1595
- NodePtr getSDKRoot () {
1596
- return RootNode;
1613
+ SDKNodeRoot* getSDKRoot () {
1614
+ return static_cast <SDKNodeRoot*>( RootNode) ;
1597
1615
}
1598
1616
1599
1617
void printTopLevelNames () {
@@ -2517,6 +2535,57 @@ class TypeMemberDiffFinder : public SDKNodeVisitor {
2517
2535
2518
2536
};
2519
2537
2538
+ // / This is to find type alias of raw types being changed to RawRepresentable.
2539
+ // / e.g. AttributeName was a typealias of String in the old SDK however it becomes
2540
+ // / a RawRepresentable struct in the new SDK.
2541
+ // / This happens typically when we use apinotes to preserve API stability by
2542
+ // / using SwiftWrapper:none in the old SDK.
2543
+ class TypeAliasDiffFinder : public SDKNodeVisitor {
2544
+ SDKNodeRoot *leftRoot;
2545
+ SDKNodeRoot *rightRoot;
2546
+ NodeMap &result;
2547
+
2548
+ static bool checkTypeMatch (const SDKNodeType* aliasType,
2549
+ const SDKNodeType* rawType) {
2550
+ StringRef Left = aliasType->getPrintedName ();
2551
+ StringRef Right = rawType->getPrintedName ();
2552
+ if (Left == " NSString" && Right == " String" )
2553
+ return true ;
2554
+ if (Left == " String" && Right == " String" )
2555
+ return true ;
2556
+ if (Left == " Int" && Right == " Int" )
2557
+ return true ;
2558
+ if (Left == " UInt" && Right == " UInt" )
2559
+ return true ;
2560
+ return false ;
2561
+ }
2562
+
2563
+ void visit (NodePtr node) override {
2564
+ auto alias = dyn_cast<SDKNodeTypeAlias>(node);
2565
+ if (!alias)
2566
+ return ;
2567
+ const SDKNodeType* aliasType = alias->getUnderlyingType ();
2568
+ for (auto *counter: rightRoot->getDescendantsByUsr (alias->getUsr ())) {
2569
+ if (auto DT = dyn_cast<SDKNodeTypeDecl>(counter)) {
2570
+ if (auto *rawType = DT->getRawValueType ()) {
2571
+ if (checkTypeMatch (aliasType, rawType)) {
2572
+ result.insert ({alias, DT});
2573
+ return ;
2574
+ }
2575
+ }
2576
+ }
2577
+ }
2578
+ }
2579
+ public:
2580
+ TypeAliasDiffFinder (SDKNodeRoot *leftRoot, SDKNodeRoot *rightRoot,
2581
+ NodeMap &result): leftRoot(leftRoot), rightRoot(rightRoot),
2582
+ result (result) {}
2583
+
2584
+ void search () {
2585
+ SDKNode::preorderVisit (leftRoot, *this );
2586
+ }
2587
+ };
2588
+
2520
2589
// Given a condition, search whether a node satisfies that condition exists
2521
2590
// in a tree.
2522
2591
class SearchVisitor : public SDKNodeVisitor {
@@ -2999,21 +3068,47 @@ class DiagnosisEmitter : public SDKNodeVisitor {
2999
3068
static void theme (raw_ostream &OS) { OS << " Type Changes" ; };
3000
3069
};
3001
3070
3071
+ struct RawRepresentableChangeDiag : public DiagBase {
3072
+ DeclKind Kind;
3073
+ StringRef DeclName;
3074
+ StringRef UnderlyingType;
3075
+ StringRef RawTypeName;
3076
+ RawRepresentableChangeDiag (MetaInfo Info, DeclKind Kind, StringRef DeclName,
3077
+ StringRef UnderlyingType, StringRef RawTypeName): DiagBase(Info),
3078
+ Kind (Kind), DeclName(DeclName), UnderlyingType(UnderlyingType),
3079
+ RawTypeName(RawTypeName) {}
3080
+ bool operator <(RawRepresentableChangeDiag Other) const {
3081
+ if (Kind != Other.Kind )
3082
+ return Kind < Other.Kind ;
3083
+ return DeclName.compare (Other.DeclName ) < 0 ;
3084
+ }
3085
+ void output () const override {
3086
+ llvm::outs () << Kind << " " << printName (DeclName)
3087
+ << " (" << UnderlyingType << " )"
3088
+ << " is now " << RawTypeName << " representable\n " ;
3089
+ }
3090
+ static void theme (raw_ostream &OS) { OS << " RawRepresentable Changes" ; };
3091
+ };
3092
+
3002
3093
std::set<SDKNodeDecl*> AddedDecls;
3003
3094
DiagBag<DeclAttrDiag> AttrChangedDecls;
3004
3095
DiagBag<DeclTypeChangeDiag> TypeChangedDecls;
3005
3096
DiagBag<RenamedDeclDiag> RenamedDecls;
3006
3097
DiagBag<MovedDeclDiag> MovedDecls;
3007
3098
DiagBag<RemovedDeclDiag> RemovedDecls;
3099
+ DiagBag<RawRepresentableChangeDiag> RawRepresentableDecls;
3008
3100
3009
3101
UpdatedNodesMap &UpdateMap;
3102
+ NodeMap &TypeAliasUpdateMap;
3010
3103
TypeMemberDiffVector &MemberChanges;
3011
- DiagnosisEmitter (UpdatedNodesMap &UpdateMap,
3012
- TypeMemberDiffVector &MemberChanges):
3013
- UpdateMap(UpdateMap), MemberChanges(MemberChanges) {}
3104
+ DiagnosisEmitter (SDKContext &Ctx, TypeMemberDiffVector &MemberChanges):
3105
+ UpdateMap(Ctx.getNodeUpdateMap()),
3106
+ TypeAliasUpdateMap(Ctx.getTypeAliasUpdateMap()),
3107
+ MemberChanges(MemberChanges){}
3108
+
3014
3109
public:
3015
3110
static void diagnosis (NodePtr LeftRoot, NodePtr RightRoot,
3016
- UpdatedNodesMap &UpdateMap );
3111
+ SDKContext &Ctx );
3017
3112
};
3018
3113
3019
3114
void DiagnosisEmitter::collectAddedDecls (NodePtr Root,
@@ -3130,11 +3225,11 @@ void DiagnosisEmitter::DeclAttrDiag::output() const {
3130
3225
}
3131
3226
3132
3227
void DiagnosisEmitter::diagnosis (NodePtr LeftRoot, NodePtr RightRoot,
3133
- UpdatedNodesMap &UpdateMap ) {
3228
+ SDKContext &Ctx ) {
3134
3229
// Find member hoist changes to help refine diagnostics.
3135
3230
TypeMemberDiffVector MemberChanges;
3136
3231
findTypeMemberDiffs (LeftRoot, RightRoot, MemberChanges);
3137
- DiagnosisEmitter Emitter (UpdateMap , MemberChanges);
3232
+ DiagnosisEmitter Emitter (Ctx , MemberChanges);
3138
3233
collectAddedDecls (RightRoot, Emitter.AddedDecls );
3139
3234
SDKNode::postorderVisit (LeftRoot, Emitter);
3140
3235
}
@@ -3171,6 +3266,19 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
3171
3266
return ;
3172
3267
}
3173
3268
3269
+ // If a type alias of a raw type has been changed to a struct/enum that
3270
+ // conforms to RawRepresentable in the later version of SDK, we show the
3271
+ // refine diagnostics message instead of showing the type alias has been
3272
+ // removed.
3273
+ if (TypeAliasUpdateMap.find ((SDKNode*)Node) != TypeAliasUpdateMap.end ()) {
3274
+ RawRepresentableDecls.Diags .emplace_back (ScreenInfo, Node->getDeclKind (),
3275
+ Node->getFullyQualifiedName (),
3276
+ Node->getAs <SDKNodeTypeAlias>()->getUnderlyingType ()->getPrintedName (),
3277
+ TypeAliasUpdateMap[(SDKNode*)Node]->getAs <SDKNodeTypeDecl>()->
3278
+ getRawValueType ()->getPrintedName ());
3279
+ return ;
3280
+ }
3281
+
3174
3282
// We should exlude those declarations that are pulled up to the super classes.
3175
3283
bool FoundInSuperclass = false ;
3176
3284
if (auto PD = dyn_cast<SDKNodeDecl>(Node->getParent ())) {
@@ -3438,11 +3546,13 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath) {
3438
3546
RightCollector.deSerialize (RightPath);
3439
3547
auto LeftModule = LeftCollector.getSDKRoot ();
3440
3548
auto RightModule = RightCollector.getSDKRoot ();
3549
+ TypeAliasDiffFinder (LeftModule, RightModule,
3550
+ Ctx.getTypeAliasUpdateMap ()).search ();
3441
3551
PrunePass Prune (Ctx.getNodeUpdateMap ());
3442
3552
Prune.pass (LeftModule, RightModule);
3443
3553
ChangeRefinementPass RefinementPass (Ctx.getNodeUpdateMap ());
3444
3554
RefinementPass.pass (LeftModule, RightModule);
3445
- DiagnosisEmitter::diagnosis (LeftModule, RightModule, Ctx. getNodeUpdateMap () );
3555
+ DiagnosisEmitter::diagnosis (LeftModule, RightModule, Ctx);
3446
3556
return 0 ;
3447
3557
}
3448
3558
0 commit comments