@@ -54,6 +54,16 @@ struct swift::ide::api::SDKNodeInitInfo {
5454 SDKNode* createSDKNode (SDKNodeKind Kind);
5555};
5656
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+
5767SDKContext::SDKContext (CheckerOptions Opts): Diags(SourceMgr), Opts(Opts) {}
5868
5969DiagnosticEngine &SDKContext::getDiags (SourceLoc Loc) {
@@ -827,6 +837,25 @@ static bool hasSameParameterFlags(const SDKNodeType *Left, const SDKNodeType *Ri
827837 return true ;
828838}
829839
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+
830859static bool isSDKNodeEqual (SDKContext &Ctx, const SDKNode &L, const SDKNode &R) {
831860 auto *LeftAlias = dyn_cast<SDKNodeTypeAlias>(&L);
832861 auto *RightAlias = dyn_cast<SDKNodeTypeAlias>(&R);
@@ -966,6 +995,8 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
966995 case SDKNodeKind::TypeWitness:
967996 case SDKNodeKind::DeclImport:
968997 case SDKNodeKind::Root: {
998+ if (isFromExtensionChanged (L, R))
999+ return false ;
9691000 return L.getPrintedName () == R.getPrintedName () &&
9701001 L.hasSameChildren (R);
9711002 }
@@ -2621,6 +2652,23 @@ void swift::ide::api::SDKNodeDeclAbstractFunc::diagnose(SDKNode *Right) {
26212652 if (reqNewWitnessTableEntry () != R->reqNewWitnessTableEntry ()) {
26222653 emitDiag (Loc, diag::decl_new_witness_table_entry, reqNewWitnessTableEntry ());
26232654 }
2655+
2656+ // Diagnose moving a non-final class member to an extension.
2657+ if (hasValidParentPtr (getKind ())) {
2658+ while (auto *parent = dyn_cast<SDKNodeDecl>(getParent ())) {
2659+ if (parent->getDeclKind () != DeclKind::Class) {
2660+ break ;
2661+ }
2662+ if (hasDeclAttribute (DeclAttrKind::DAK_Final)) {
2663+ break ;
2664+ }
2665+ auto result = isFromExtensionChanged (*this , *Right);
2666+ if (result.hasValue () && *result) {
2667+ emitDiag (Loc, diag::class_member_moved_to_extension);
2668+ }
2669+ break ;
2670+ }
2671+ }
26242672 }
26252673}
26262674
0 commit comments