Skip to content

Commit 03bd71c

Browse files
authored
Merge pull request swiftlang#26910 from nkcsgexi/diagnose-objc-name-change
ABI/API checker: diagnose ObjC name changes as breakages
2 parents 7039277 + 6374d36 commit 03bd71c

File tree

15 files changed

+187
-9
lines changed

15 files changed

+187
-9
lines changed

include/swift/AST/DiagnosticsModuleDiffer.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ ERROR(decl_new_witness_table_entry,none,"%0 now requires %select{|no}1 new witne
9696

9797
ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef))
9898

99+
ERROR(objc_name_change,none,"%0 has ObjC name change from %1 to %2", (StringRef, StringRef, StringRef))
100+
99101
#ifndef DIAG_NO_UNDEF
100102
# if defined(DIAG)
101103
# undef DIAG

include/swift/IDE/DigesterEnums.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ KEY_STRING(IntroiOS, intro_iOS)
151151
KEY_STRING(IntrotvOS, intro_tvOS)
152152
KEY_STRING(IntrowatchOS, intro_watchOS)
153153
KEY_STRING(Introswift, intro_swift)
154+
KEY_STRING(ObjCName, objc_name)
154155

155156
KEY_STRING_ARR(SuperclassNames, superclassNames)
156157
KEY_STRING_ARR(ToolArgs, tool_arguments)

test/api-digester/Inputs/cake.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public protocol P1 {}
44
public protocol P2 {}
55
public protocol P3: P2, P1 {}
6+
67
@frozen
78
public struct S1: P1 {
89
public static func foo1() {}
@@ -123,3 +124,9 @@ public class PlatformIntroClass {}
123124

124125
@available(swift, introduced: 5)
125126
public class SwiftIntroClass {}
127+
128+
@objc(NewObjCClass)
129+
public class SwiftObjcClass {
130+
@objc(ObjCFool:ObjCA:ObjCB:)
131+
public func foo(a:Int, b:Int, c: Int) {}
132+
}

test/api-digester/Inputs/cake_baseline/cake.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,9 @@ public class Zoo {
195195
}
196196

197197
public func returnFunctionTypeOwnershipChange() -> (C1) -> () { return { _ in } }
198+
199+
@objc(OldObjCClass)
200+
public class SwiftObjcClass {
201+
@objc(OldObjCFool:OldObjCA:OldObjCB:)
202+
public func foo(a:Int, b:Int, c: Int) {}
203+
}

test/api-digester/Inputs/cake_current/cake.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,9 @@ public class Zoo {
202202
}
203203

204204
public func returnFunctionTypeOwnershipChange() -> (__owned C1) -> () { return { _ in } }
205+
206+
@objc(NewObjCClass)
207+
public class SwiftObjcClass {
208+
@objc(NewObjCFool:NewObjCA:NewObjCB:)
209+
public func foo(a:Int, b:Int, c: Int) {}
210+
}

test/api-digester/Outputs/Cake-abi.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ cake: InfixOperator ..*.. has been changed to a PrefixOperator
2727
cake: Protocol ProtocolToEnum has been changed to a Enum
2828

2929
/* Renamed Decls */
30+
cake: Class SwiftObjcClass has ObjC name change from OldObjCClass to NewObjCClass
3031
cake: Func S1.foo5(x:y:) has been renamed to Func foo5(x:y:z:)
32+
cake: Func SwiftObjcClass.foo(a:b:c:) has ObjC name change from OldObjCFool:OldObjCA:OldObjCB: to NewObjCFool:NewObjCA:NewObjCB:
3133
cake: Struct Somestruct2 has been renamed to Struct NSSomestruct2
3234

3335
/* Type Changes */

test/api-digester/Outputs/Cake.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ cake: InfixOperator ..*.. has been changed to a PrefixOperator
2222
cake: Protocol ProtocolToEnum has been changed to a Enum
2323

2424
/* Renamed Decls */
25+
cake: Class SwiftObjcClass has ObjC name change from OldObjCClass to NewObjCClass
2526
cake: Func S1.foo5(x:y:) has been renamed to Func foo5(x:y:z:)
27+
cake: Func SwiftObjcClass.foo(a:b:c:) has ObjC name change from OldObjCFool:OldObjCA:OldObjCB: to NewObjCFool:NewObjCA:NewObjCB:
2628
cake: Struct Somestruct2 has been renamed to Struct NSSomestruct2
2729

2830
/* Type Changes */

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

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,58 @@
14311431
"Available"
14321432
]
14331433
},
1434+
{
1435+
"kind": "TypeDecl",
1436+
"name": "SwiftObjcClass",
1437+
"printedName": "SwiftObjcClass",
1438+
"children": [
1439+
{
1440+
"kind": "Function",
1441+
"name": "foo",
1442+
"printedName": "foo(a:b:c:)",
1443+
"children": [
1444+
{
1445+
"kind": "TypeNominal",
1446+
"name": "Void",
1447+
"printedName": "()"
1448+
},
1449+
{
1450+
"kind": "TypeNominal",
1451+
"name": "Int",
1452+
"printedName": "Swift.Int",
1453+
"usr": "s:Si"
1454+
},
1455+
{
1456+
"kind": "TypeNominal",
1457+
"name": "Int",
1458+
"printedName": "Swift.Int",
1459+
"usr": "s:Si"
1460+
},
1461+
{
1462+
"kind": "TypeNominal",
1463+
"name": "Int",
1464+
"printedName": "Swift.Int",
1465+
"usr": "s:Si"
1466+
}
1467+
],
1468+
"declKind": "Func",
1469+
"usr": "c:@M@cake@objc(cs)NewObjCClass(im)ObjCFool:ObjCA:ObjCB:",
1470+
"moduleName": "cake",
1471+
"objc_name": "ObjCFool:ObjCA:ObjCB:",
1472+
"declAttributes": [
1473+
"ObjC"
1474+
],
1475+
"funcSelfKind": "NonMutating"
1476+
}
1477+
],
1478+
"declKind": "Class",
1479+
"usr": "c:@M@cake@objc(cs)NewObjCClass",
1480+
"moduleName": "cake",
1481+
"objc_name": "NewObjCClass",
1482+
"declAttributes": [
1483+
"ObjC"
1484+
]
1485+
},
14341486
{
14351487
"kind": "TypeDecl",
14361488
"name": "Int",
@@ -1771,5 +1823,5 @@
17711823
]
17721824
}
17731825
],
1774-
"json_format_version": 3
1826+
"json_format_version": 4
17751827
}

test/api-digester/Outputs/cake.json

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,58 @@
12791279
"Available"
12801280
]
12811281
},
1282+
{
1283+
"kind": "TypeDecl",
1284+
"name": "SwiftObjcClass",
1285+
"printedName": "SwiftObjcClass",
1286+
"children": [
1287+
{
1288+
"kind": "Function",
1289+
"name": "foo",
1290+
"printedName": "foo(a:b:c:)",
1291+
"children": [
1292+
{
1293+
"kind": "TypeNominal",
1294+
"name": "Void",
1295+
"printedName": "()"
1296+
},
1297+
{
1298+
"kind": "TypeNominal",
1299+
"name": "Int",
1300+
"printedName": "Swift.Int",
1301+
"usr": "s:Si"
1302+
},
1303+
{
1304+
"kind": "TypeNominal",
1305+
"name": "Int",
1306+
"printedName": "Swift.Int",
1307+
"usr": "s:Si"
1308+
},
1309+
{
1310+
"kind": "TypeNominal",
1311+
"name": "Int",
1312+
"printedName": "Swift.Int",
1313+
"usr": "s:Si"
1314+
}
1315+
],
1316+
"declKind": "Func",
1317+
"usr": "c:@M@cake@objc(cs)NewObjCClass(im)ObjCFool:ObjCA:ObjCB:",
1318+
"moduleName": "cake",
1319+
"objc_name": "ObjCFool:ObjCA:ObjCB:",
1320+
"declAttributes": [
1321+
"ObjC"
1322+
],
1323+
"funcSelfKind": "NonMutating"
1324+
}
1325+
],
1326+
"declKind": "Class",
1327+
"usr": "c:@M@cake@objc(cs)NewObjCClass",
1328+
"moduleName": "cake",
1329+
"objc_name": "NewObjCClass",
1330+
"declAttributes": [
1331+
"ObjC"
1332+
]
1333+
},
12821334
{
12831335
"kind": "TypeDecl",
12841336
"name": "Int",
@@ -1622,5 +1674,5 @@
16221674
]
16231675
}
16241676
],
1625-
"json_format_version": 3
1677+
"json_format_version": 4
16261678
}

test/api-digester/Outputs/clang-module-dump.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"moduleName": "Foo",
3232
"genericSig": "<Self where Self : Foo.AnotherObjcProt>",
3333
"protocolReq": true,
34+
"objc_name": "anotherFunctionFromProt",
3435
"declAttributes": [
3536
"ObjC"
3637
],
@@ -41,6 +42,7 @@
4142
"declKind": "Protocol",
4243
"usr": "c:objc(pl)AnotherObjcProt",
4344
"moduleName": "Foo",
45+
"objc_name": "AnotherObjcProt",
4446
"declAttributes": [
4547
"ObjC"
4648
]
@@ -72,6 +74,7 @@
7274
"usr": "c:objc(cs)ClangInterface(im)someFunction",
7375
"moduleName": "Foo",
7476
"isOpen": true,
77+
"objc_name": "someFunction",
7578
"declAttributes": [
7679
"ObjC"
7780
],
@@ -94,6 +97,7 @@
9497
"moduleName": "Foo",
9598
"overriding": true,
9699
"implicit": true,
100+
"objc_name": "init",
97101
"declAttributes": [
98102
"Override",
99103
"ObjC"
@@ -104,6 +108,7 @@
104108
"usr": "c:objc(cs)ClangInterface",
105109
"moduleName": "Foo",
106110
"isOpen": true,
111+
"objc_name": "ClangInterface",
107112
"declAttributes": [
108113
"ObjC"
109114
],
@@ -154,6 +159,7 @@
154159
"moduleName": "Foo",
155160
"genericSig": "<Self where Self : Foo.ObjcProt>",
156161
"protocolReq": true,
162+
"objc_name": "someFunctionFromProt",
157163
"declAttributes": [
158164
"ObjC"
159165
],
@@ -164,10 +170,11 @@
164170
"declKind": "Protocol",
165171
"usr": "c:objc(pl)ObjcProt",
166172
"moduleName": "Foo",
173+
"objc_name": "ObjcProt",
167174
"declAttributes": [
168175
"ObjC"
169176
]
170177
}
171178
],
172-
"json_format_version": 3
179+
"json_format_version": 4
173180
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"kind": "Root",
33
"name": "TopLevel",
44
"printedName": "TopLevel",
5-
"json_format_version": 3
5+
"json_format_version": 4
66
}

tools/swift-api-digester/ModuleAnalyzerNodes.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ SDKNodeDecl::SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind)
109109
SugaredGenericSig(Info.SugaredGenericSig),
110110
FixedBinaryOrder(Info.FixedBinaryOrder),
111111
introVersions({Info.IntromacOS, Info.IntroiOS, Info.IntrotvOS,
112-
Info.IntrowatchOS, Info.Introswift}){}
112+
Info.IntrowatchOS, Info.Introswift}),
113+
ObjCName(Info.ObjCName) {}
113114

114115
SDKNodeType::SDKNodeType(SDKNodeInitInfo Info, SDKNodeKind Kind):
115116
SDKNode(Info, Kind), TypeAttributes(Info.TypeAttrs),
@@ -915,6 +916,8 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
915916
return false;
916917
if (Left->isInternal() != Right->isInternal())
917918
return false;
919+
if (Left->getObjCName() != Right->getObjCName())
920+
return false;
918921
if (Left->hasFixedBinaryOrder() != Right->hasFixedBinaryOrder())
919922
return false;
920923
if (Left->hasFixedBinaryOrder()) {
@@ -1252,6 +1255,16 @@ StringRef SDKContext::getLanguageIntroVersion(Decl *D) {
12521255
return getLanguageIntroVersion(D->getDeclContext()->getAsDecl());
12531256
}
12541257

1258+
StringRef SDKContext::getObjcName(Decl *D) {
1259+
if (auto *OC = D->getAttrs().getAttribute<ObjCAttr>()) {
1260+
if (OC->getName().hasValue()) {
1261+
SmallString<32> Buffer;
1262+
return buffer(OC->getName()->getString(Buffer));
1263+
}
1264+
}
1265+
return StringRef();
1266+
}
1267+
12551268
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Type Ty, TypeInitInfo Info) :
12561269
Ctx(Ctx), Name(getTypeName(Ctx, Ty, Info.IsImplicitlyUnwrappedOptional)),
12571270
PrintedName(getPrintedName(Ctx, Ty, Info.IsImplicitlyUnwrappedOptional)),
@@ -1278,6 +1291,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Decl *D):
12781291
IntrotvOS(Ctx.getPlatformIntroVersion(D, PlatformKind::tvOS)),
12791292
IntrowatchOS(Ctx.getPlatformIntroVersion(D, PlatformKind::watchOS)),
12801293
Introswift(Ctx.getLanguageIntroVersion(D)),
1294+
ObjCName(Ctx.getObjcName(D)),
12811295
IsImplicit(D->isImplicit()),
12821296
IsDeprecated(D->getAttrs().getDeprecated(D->getASTContext())),
12831297
IsABIPlaceholder(isABIPlaceholderRecursive(D)) {
@@ -1901,6 +1915,7 @@ void SDKNodeDecl::jsonize(json::Output &out) {
19011915
output(out, KeyKind::KK_intro_tvOS, introVersions.tvos);
19021916
output(out, KeyKind::KK_intro_watchOS, introVersions.watchos);
19031917
output(out, KeyKind::KK_intro_swift, introVersions.swift);
1918+
output(out, KeyKind::KK_objc_name, ObjCName);
19041919
out.mapOptional(getKeyContent(Ctx, KeyKind::KK_declAttributes).data(), DeclAttributes);
19051920
out.mapOptional(getKeyContent(Ctx, KeyKind::KK_fixedbinaryorder).data(), FixedBinaryOrder);
19061921
// Strong reference is implied, no need for serialization.

tools/swift-api-digester/ModuleAnalyzerNodes.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ namespace api {
6262
///
6363
/// When the json format changes in a way that requires version-specific handling, this number should be incremented.
6464
/// This ensures we could have backward compatibility so that version changes in the format won't stop the checker from working.
65-
const uint8_t DIGESTER_JSON_VERSION = 3; // Use fully qualifed type names for all json outputs
65+
const uint8_t DIGESTER_JSON_VERSION = 4; // Add objc_name field
6666
const uint8_t DIGESTER_JSON_DEFAULT_VERSION = 0; // Use this version number for files before we have a version number in json.
6767

6868
class SDKNode;
@@ -172,7 +172,8 @@ class SDKContext {
172172

173173
CheckerOptions Opts;
174174
std::vector<BreakingAttributeInfo> BreakingAttrs;
175-
175+
// The common version of two ABI/API descriptors under comparison.
176+
Optional<uint8_t> CommonVersion;
176177
public:
177178
// Define the set of known identifiers.
178179
#define IDENTIFIER_WITH_NAME(Name, IdStr) StringRef Id_##Name = IdStr;
@@ -204,8 +205,19 @@ class SDKContext {
204205
DiagnosticEngine &getDiags() {
205206
return Diags;
206207
}
208+
void setCommonVersion(uint8_t Ver) {
209+
assert(!CommonVersion.hasValue());
210+
CommonVersion = Ver;
211+
}
212+
uint8_t getCommonVersion() const {
213+
return *CommonVersion;
214+
}
215+
bool commonVersionAtLeast(uint8_t Ver) const {
216+
return getCommonVersion() >= Ver;
217+
}
207218
StringRef getPlatformIntroVersion(Decl *D, PlatformKind Kind);
208219
StringRef getLanguageIntroVersion(Decl *D);
220+
StringRef getObjcName(Decl *D);
209221
bool isEqual(const SDKNode &Left, const SDKNode &Right);
210222
bool checkingABI() const { return Opts.ABI; }
211223
AccessLevel getAccessLevel(const ValueDecl *VD) const;
@@ -343,6 +355,7 @@ class SDKNodeDecl: public SDKNode {
343355
StringRef SugaredGenericSig;
344356
Optional<uint8_t> FixedBinaryOrder;
345357
PlatformIntroVersion introVersions;
358+
StringRef ObjCName;
346359

347360
protected:
348361
SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind);
@@ -379,6 +392,7 @@ class SDKNodeDecl: public SDKNode {
379392
bool hasFixedBinaryOrder() const { return FixedBinaryOrder.hasValue(); }
380393
uint8_t getFixedBinaryOrder() const { return *FixedBinaryOrder; }
381394
PlatformIntroVersion getIntroducingVersion() const { return introVersions; }
395+
StringRef getObjCName() const { return ObjCName; }
382396
virtual void jsonize(json::Output &Out) override;
383397
virtual void diagnose(SDKNode *Right) override;
384398

tools/swift-api-digester/ModuleDiagsConsumer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static StringRef getCategoryName(uint32_t ID) {
3838
case LocalDiagID::decl_kind_changed:
3939
return "/* Moved Decls */";
4040
case LocalDiagID::renamed_decl:
41+
case LocalDiagID::objc_name_change:
4142
return "/* Renamed Decls */";
4243
case LocalDiagID::decl_attr_change:
4344
case LocalDiagID::decl_new_attr:

0 commit comments

Comments
 (0)