@@ -54,6 +54,16 @@ struct swift::ide::api::SDKNodeInitInfo {
54
54
SDKNode* createSDKNode (SDKNodeKind Kind);
55
55
};
56
56
57
+ bool swift::ide::api::hasValidParentPtr (SDKNodeKind kind) {
58
+ switch (kind) {
59
+ case SDKNodeKind::Conformance:
60
+ case SDKNodeKind::DeclAccessor:
61
+ return false ;
62
+ default :
63
+ return true ;
64
+ }
65
+ }
66
+
57
67
SDKContext::SDKContext (CheckerOptions Opts): Diags(SourceMgr), Opts(Opts) {}
58
68
59
69
DiagnosticEngine &SDKContext::getDiags (SourceLoc Loc) {
@@ -827,6 +837,25 @@ static bool hasSameParameterFlags(const SDKNodeType *Left, const SDKNodeType *Ri
827
837
return true ;
828
838
}
829
839
840
+ // Return whether a decl has been moved in/out to an extension
841
+ static Optional<bool > isFromExtensionChanged (const SDKNode &L, const SDKNode &R) {
842
+ assert (L.getKind () == R.getKind ());
843
+ // Version 8 starts to include whether a decl is from an extension.
844
+ if (L.getJsonFormatVersion () + R.getJsonFormatVersion () < 2 * 8 ) {
845
+ return llvm::None;
846
+ }
847
+ auto *Left = dyn_cast<SDKNodeDecl>(&L);
848
+ auto *Right = dyn_cast<SDKNodeDecl>(&R);
849
+ if (!Left) {
850
+ return llvm::None;
851
+ }
852
+ if (Left->isFromExtension () == Right->isFromExtension ()) {
853
+ return llvm::None;
854
+ } else {
855
+ return Right->isFromExtension ();
856
+ }
857
+ }
858
+
830
859
static bool isSDKNodeEqual (SDKContext &Ctx, const SDKNode &L, const SDKNode &R) {
831
860
auto *LeftAlias = dyn_cast<SDKNodeTypeAlias>(&L);
832
861
auto *RightAlias = dyn_cast<SDKNodeTypeAlias>(&R);
@@ -966,6 +995,8 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
966
995
case SDKNodeKind::TypeWitness:
967
996
case SDKNodeKind::DeclImport:
968
997
case SDKNodeKind::Root: {
998
+ if (isFromExtensionChanged (L, R))
999
+ return false ;
969
1000
return L.getPrintedName () == R.getPrintedName () &&
970
1001
L.hasSameChildren (R);
971
1002
}
@@ -2619,6 +2650,23 @@ void swift::ide::api::SDKNodeDeclAbstractFunc::diagnose(SDKNode *Right) {
2619
2650
if (reqNewWitnessTableEntry () != R->reqNewWitnessTableEntry ()) {
2620
2651
emitDiag (Loc, diag::decl_new_witness_table_entry, reqNewWitnessTableEntry ());
2621
2652
}
2653
+
2654
+ // Diagnose moving a non-final class member to an extension.
2655
+ if (hasValidParentPtr (getKind ())) {
2656
+ while (auto *parent = dyn_cast<SDKNodeDecl>(getParent ())) {
2657
+ if (parent->getDeclKind () != DeclKind::Class) {
2658
+ break ;
2659
+ }
2660
+ if (hasDeclAttribute (DeclAttrKind::DAK_Final)) {
2661
+ break ;
2662
+ }
2663
+ auto result = isFromExtensionChanged (*this , *Right);
2664
+ if (result.hasValue () && *result) {
2665
+ emitDiag (Loc, diag::class_member_moved_to_extension);
2666
+ }
2667
+ break ;
2668
+ }
2669
+ }
2622
2670
}
2623
2671
}
2624
2672
0 commit comments