Skip to content

Commit 399d5f3

Browse files
authored
Merge pull request #59258 from nkcsgexi/abi-checker-fix-extension
2 parents b488e07 + 7bab30c commit 399d5f3

File tree

8 files changed

+113
-5
lines changed

8 files changed

+113
-5
lines changed

include/swift/APIDigester/ModuleAnalyzerNodes.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ namespace api {
6363
///
6464
/// When the json format changes in a way that requires version-specific handling, this number should be incremented.
6565
/// This ensures we could have backward compatibility so that version changes in the format won't stop the checker from working.
66-
const uint8_t DIGESTER_JSON_VERSION = 7; // push SDKNodeRoot to lower-level
66+
const uint8_t DIGESTER_JSON_VERSION = 8; // add isFromExtension
6767
const uint8_t DIGESTER_JSON_DEFAULT_VERSION = 0; // Use this version number for files before we have a version number in json.
6868
const StringRef ABIRootKey = "ABIRoot";
6969
const StringRef ConstValuesKey = "ConstValues";
@@ -354,6 +354,7 @@ class SDKNodeDecl: public SDKNode {
354354
bool IsOpen;
355355
bool IsInternal;
356356
bool IsABIPlaceholder;
357+
bool IsFromExtension;
357358
uint8_t ReferenceOwnership;
358359
StringRef GenericSig;
359360
// In ABI mode, this field is populated as a user-friendly version of GenericSig.
@@ -392,6 +393,7 @@ class SDKNodeDecl: public SDKNode {
392393
bool isOpen() const { return IsOpen; }
393394
bool isInternal() const { return IsInternal; }
394395
bool isABIPlaceholder() const { return IsABIPlaceholder; }
396+
bool isFromExtension() const { return IsFromExtension; }
395397
StringRef getGenericSignature() const { return GenericSig; }
396398
StringRef getSugaredGenericSignature() const { return SugaredGenericSig; }
397399
StringRef getScreenInfo() const;
@@ -710,6 +712,7 @@ class SDKNodeDeclConstructor: public SDKNodeDeclAbstractFunc {
710712
void jsonize(json::Output &Out) override;
711713
};
712714

715+
// Note: Accessor doesn't have Parent pointer.
713716
class SDKNodeDeclAccessor: public SDKNodeDeclAbstractFunc {
714717
SDKNodeDecl *Owner;
715718
AccessorKind AccKind;
@@ -828,6 +831,8 @@ int findDeclUsr(StringRef dumpPath, CheckerOptions Opts);
828831

829832
void nodeSetDifference(ArrayRef<SDKNode*> Left, ArrayRef<SDKNode*> Right,
830833
NodeVector &LeftMinusRight, NodeVector &RightMinusLeft);
834+
835+
bool hasValidParentPtr(SDKNodeKind kind);
831836
} // end of abi namespace
832837
} // end of ide namespace
833838
} // end of Swift namespace

include/swift/AST/DiagnosticsModuleDiffer.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ ERROR(type_witness_change,APIDigesterBreakage,"%0 has type witness type for %1 c
7676

7777
ERROR(decl_new_witness_table_entry,APIDigesterBreakage,"%0 now requires%select{| no}1 new witness table entry", (StringRef, bool))
7878

79+
ERROR(class_member_moved_to_extension,APIDigesterBreakage,"Non-final class member %0 is moved to extension", (StringRef))
80+
7981
WARNING(new_decl_without_intro,APIDigesterBreakage,"%0 is a new API without @available attribute", (StringRef))
8082

8183
ERROR(objc_name_change,APIDigesterBreakage,"%0 has ObjC name change from %1 to %2", (StringRef, StringRef, StringRef))

include/swift/IDE/DigesterEnums.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ KEY_BOOL(IsExternal, isExternal)
136136
KEY_BOOL(IsEnumExhaustive, isEnumExhaustive)
137137
KEY_BOOL(HasMissingDesignatedInitializers, hasMissingDesignatedInitializers)
138138
KEY_BOOL(InheritsConvenienceInitializers, inheritsConvenienceInitializers)
139+
KEY_BOOL(IsFromExtension, isFromExtension)
139140

140141
KEY(kind)
141142

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
5767
SDKContext::SDKContext(CheckerOptions Opts): Diags(SourceMgr), Opts(Opts) {}
5868

5969
DiagnosticEngine &SDKContext::getDiags(SourceLoc Loc) {
@@ -109,6 +119,7 @@ SDKNodeDecl::SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind)
109119
IsOverriding(Info.IsOverriding),
110120
IsOpen(Info.IsOpen),
111121
IsInternal(Info.IsInternal), IsABIPlaceholder(Info.IsABIPlaceholder),
122+
IsFromExtension(Info.IsFromExtension),
112123
ReferenceOwnership(uint8_t(Info.ReferenceOwnership)),
113124
GenericSig(Info.GenericSig),
114125
SugaredGenericSig(Info.SugaredGenericSig),
@@ -826,6 +837,25 @@ static bool hasSameParameterFlags(const SDKNodeType *Left, const SDKNodeType *Ri
826837
return true;
827838
}
828839

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+
829859
static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R) {
830860
auto *LeftAlias = dyn_cast<SDKNodeTypeAlias>(&L);
831861
auto *RightAlias = dyn_cast<SDKNodeTypeAlias>(&R);
@@ -965,6 +995,8 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
965995
case SDKNodeKind::TypeWitness:
966996
case SDKNodeKind::DeclImport:
967997
case SDKNodeKind::Root: {
998+
if (isFromExtensionChanged(L, R))
999+
return false;
9681000
return L.getPrintedName() == R.getPrintedName() &&
9691001
L.hasSameChildren(R);
9701002
}
@@ -1376,6 +1408,13 @@ StringRef SDKContext::getInitKind(Decl *D) {
13761408
return StringRef();
13771409
}
13781410

1411+
static bool isDeclaredInExtension(Decl *D) {
1412+
if (auto *DC = D->getDeclContext()->getAsDecl()) {
1413+
return isa<ExtensionDecl>(DC);
1414+
}
1415+
return false;
1416+
}
1417+
13791418
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Decl *D):
13801419
Ctx(Ctx), DKind(D->getKind()), Loc(D->getLoc()),
13811420
Location(calculateLocation(Ctx, D)),
@@ -1394,6 +1433,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Decl *D):
13941433
IsImplicit(D->isImplicit()),
13951434
IsDeprecated(D->getAttrs().getDeprecated(D->getASTContext())),
13961435
IsABIPlaceholder(isABIPlaceholderRecursive(D)),
1436+
IsFromExtension(isDeclaredInExtension(D)),
13971437
DeclAttrs(collectDeclAttributes(D)) {}
13981438

13991439
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, OperatorDecl *OD):
@@ -2040,6 +2080,7 @@ void SDKNodeDecl::jsonize(json::Output &out) {
20402080
uint8_t Raw = uint8_t(getReferenceOwnership());
20412081
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_ownership).data(), Raw);
20422082
}
2083+
output(out, KeyKind::KK_isFromExtension, IsFromExtension);
20432084
}
20442085

20452086
void SDKNodeDeclAbstractFunc::jsonize(json::Output &out) {
@@ -2611,6 +2652,23 @@ void swift::ide::api::SDKNodeDeclAbstractFunc::diagnose(SDKNode *Right) {
26112652
if (reqNewWitnessTableEntry() != R->reqNewWitnessTableEntry()) {
26122653
emitDiag(Loc, diag::decl_new_witness_table_entry, reqNewWitnessTableEntry());
26132654
}
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+
}
26142672
}
26152673
}
26162674

test/api-digester/Outputs/cake-abi.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"genericSig": "<τ_0_0 where τ_0_0 : cake.P1>",
6565
"sugared_genericSig": "<Self where Self : cake.P1>",
6666
"static": true,
67+
"isFromExtension": true,
6768
"funcSelfKind": "NonMutating"
6869
}
6970
],
@@ -219,6 +220,7 @@
219220
"moduleName": "cake",
220221
"genericSig": "<τ_0_0, τ_0_1, τ_0_2 where τ_0_0 == cake.S1, τ_0_1 == cake.S1, τ_0_2 == cake.S1>",
221222
"sugared_genericSig": "<T1, T2, T3 where T1 == cake.S1, T2 == cake.S1, T3 == cake.S1>",
223+
"isFromExtension": true,
222224
"funcSelfKind": "NonMutating"
223225
},
224226
{
@@ -238,6 +240,7 @@
238240
"moduleName": "cake",
239241
"genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
240242
"sugared_genericSig": "<T1, T2, T3>",
243+
"isFromExtension": true,
241244
"funcSelfKind": "NonMutating"
242245
}
243246
],
@@ -1021,6 +1024,7 @@
10211024
"moduleName": "cake",
10221025
"genericSig": "<τ_0_0 where τ_0_0 : cake.ProWithAssociatedType>",
10231026
"sugared_genericSig": "<Self where Self : cake.ProWithAssociatedType>",
1027+
"isFromExtension": true,
10241028
"funcSelfKind": "NonMutating"
10251029
},
10261030
{
@@ -1039,6 +1043,7 @@
10391043
"usr": "s:4cake21ProWithAssociatedTypePAAE9NonReqVarSivp",
10401044
"mangledName": "$s4cake21ProWithAssociatedTypePAAE9NonReqVarSivp",
10411045
"moduleName": "cake",
1046+
"isFromExtension": true,
10421047
"accessors": [
10431048
{
10441049
"kind": "Accessor",
@@ -1058,6 +1063,7 @@
10581063
"moduleName": "cake",
10591064
"genericSig": "<τ_0_0 where τ_0_0 : cake.ProWithAssociatedType>",
10601065
"sugared_genericSig": "<Self where Self : cake.ProWithAssociatedType>",
1066+
"isFromExtension": true,
10611067
"accessorKind": "get"
10621068
}
10631069
]
@@ -1305,6 +1311,7 @@
13051311
"moduleName": "cake",
13061312
"genericSig": "<τ_0_0 where τ_0_0 : cake.PSuper>",
13071313
"sugared_genericSig": "<Self where Self : cake.PSuper>",
1314+
"isFromExtension": true,
13081315
"funcSelfKind": "NonMutating"
13091316
}
13101317
],
@@ -1648,6 +1655,7 @@
16481655
"usr": "s:Si4cakeE3fooyyF",
16491656
"mangledName": "$sSi4cakeE3fooyyF",
16501657
"moduleName": "cake",
1658+
"isFromExtension": true,
16511659
"funcSelfKind": "NonMutating"
16521660
},
16531661
{
@@ -1665,6 +1673,7 @@
16651673
"usr": "s:Si4cakeE3baryyF",
16661674
"mangledName": "$sSi4cakeE3baryyF",
16671675
"moduleName": "cake",
1676+
"isFromExtension": true,
16681677
"funcSelfKind": "NonMutating"
16691678
}
16701679
],
@@ -2008,6 +2017,6 @@
20082017
]
20092018
}
20102019
],
2011-
"json_format_version": 7
2020+
"json_format_version": 8
20122021
}
20132022
}

test/api-digester/Outputs/cake.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"moduleName": "cake",
6464
"genericSig": "<Self where Self : cake.P1>",
6565
"static": true,
66+
"isFromExtension": true,
6667
"funcSelfKind": "NonMutating"
6768
}
6869
],
@@ -223,6 +224,7 @@
223224
"mangledName": "$s4cake2C0CA2A2S1VRszAERs_AERs0_rlE17conditionalFooExtyyF",
224225
"moduleName": "cake",
225226
"genericSig": "<T1, T2, T3 where T1 == cake.S1, T2 == cake.S1, T3 == cake.S1>",
227+
"isFromExtension": true,
226228
"funcSelfKind": "NonMutating"
227229
},
228230
{
@@ -241,6 +243,7 @@
241243
"mangledName": "$s4cake2C0C19unconditionalFooExtyyF",
242244
"moduleName": "cake",
243245
"genericSig": "<T1, T2, T3>",
246+
"isFromExtension": true,
244247
"funcSelfKind": "NonMutating"
245248
}
246249
],
@@ -921,6 +924,7 @@
921924
"mangledName": "$s4cake21ProWithAssociatedTypePAAE10NonReqFuncyyF",
922925
"moduleName": "cake",
923926
"genericSig": "<Self where Self : cake.ProWithAssociatedType>",
927+
"isFromExtension": true,
924928
"funcSelfKind": "NonMutating"
925929
},
926930
{
@@ -939,6 +943,7 @@
939943
"usr": "s:4cake21ProWithAssociatedTypePAAE9NonReqVarSivp",
940944
"mangledName": "$s4cake21ProWithAssociatedTypePAAE9NonReqVarSivp",
941945
"moduleName": "cake",
946+
"isFromExtension": true,
942947
"accessors": [
943948
{
944949
"kind": "Accessor",
@@ -957,6 +962,7 @@
957962
"mangledName": "$s4cake21ProWithAssociatedTypePAAE9NonReqVarSivg",
958963
"moduleName": "cake",
959964
"genericSig": "<Self where Self : cake.ProWithAssociatedType>",
965+
"isFromExtension": true,
960966
"accessorKind": "get"
961967
}
962968
]
@@ -977,7 +983,8 @@
977983
"usr": "s:4cake21ProWithAssociatedTypePAAE11NonReqAliasa",
978984
"mangledName": "$s4cake21ProWithAssociatedTypePAAE11NonReqAliasa",
979985
"moduleName": "cake",
980-
"genericSig": "<Self where Self : cake.ProWithAssociatedType>"
986+
"genericSig": "<Self where Self : cake.ProWithAssociatedType>",
987+
"isFromExtension": true
981988
}
982989
],
983990
"declKind": "Protocol",
@@ -1187,6 +1194,7 @@
11871194
"mangledName": "$s4cake6PSuperPAAE9futureFooyyF",
11881195
"moduleName": "cake",
11891196
"genericSig": "<Self where Self : cake.PSuper>",
1197+
"isFromExtension": true,
11901198
"funcSelfKind": "NonMutating"
11911199
}
11921200
],
@@ -1508,6 +1516,7 @@
15081516
"usr": "s:Si4cakeE3fooyyF",
15091517
"mangledName": "$sSi4cakeE3fooyyF",
15101518
"moduleName": "cake",
1519+
"isFromExtension": true,
15111520
"funcSelfKind": "NonMutating"
15121521
},
15131522
{
@@ -1525,6 +1534,7 @@
15251534
"usr": "s:Si4cakeE3baryyF",
15261535
"mangledName": "$sSi4cakeE3baryyF",
15271536
"moduleName": "cake",
1537+
"isFromExtension": true,
15281538
"funcSelfKind": "NonMutating"
15291539
}
15301540
],
@@ -1868,6 +1878,6 @@
18681878
]
18691879
}
18701880
],
1871-
"json_format_version": 7
1881+
"json_format_version": 8
18721882
}
18731883
}

test/api-digester/Outputs/empty-baseline.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
"kind": "Root",
44
"name": "TopLevel",
55
"printedName": "TopLevel",
6-
"json_format_version": 7
6+
"json_format_version": 8
77
}
88
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi-before.json %s -enable-library-evolution -DBASELINE -emit-tbd-path %t/abi-before.tbd
4+
// RUN: %target-swift-frontend -emit-module -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi-after.json %s -enable-library-evolution -emit-tbd-path %t/abi-after.tbd
5+
// RUN: %api-digester -diagnose-sdk --input-paths %t/abi-before.json -input-paths %t/abi-after.json -abi -o %t/result.txt
6+
// RUN: %FileCheck %s < %t/result.txt
7+
8+
#if BASELINE
9+
10+
public class C {
11+
public func foo() {}
12+
}
13+
14+
#else
15+
16+
public class C {}
17+
extension C {
18+
public func foo() {}
19+
}
20+
21+
#endif
22+
23+
// CHECK: Non-final class member Func C.foo() is moved to extension

0 commit comments

Comments
 (0)