Skip to content

Commit 4d73173

Browse files
Harlan HaskinsCodaFi
authored andcommitted
[api-digester] Teach the api-digester about hasMissingDesignatedInitializers
Because we won’t be serializing this attribute, add custom diagnostics for the cases where: - We add @_hasMissingDesignatedInits to an open class, which means subclasses won’t be able to inherit its inits - We remove @_inheritsConvenienceInitializers, which means APIs are removed
1 parent 511db0c commit 4d73173

File tree

14 files changed

+139
-16
lines changed

14 files changed

+139
-16
lines changed

include/swift/AST/DiagnosticsModuleDiffer.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ ERROR(objc_name_change,none,"%0 has ObjC name change from %1 to %2", (StringRef,
9898

9999
ERROR(desig_init_added,none,"%0 has been added as a designated initializer to an open class", (StringRef))
100100

101+
ERROR(added_invisible_designated_init,none,"%0 has new designated initializers that are not visible to clients", (StringRef))
102+
103+
ERROR(not_inheriting_convenience_inits,none,"%0 no longer inherits convenience inits from its superclass", (StringRef))
104+
101105
#ifndef DIAG_NO_UNDEF
102106
# if defined(DIAG)
103107
# undef DIAG

include/swift/IDE/DigesterEnums.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ KEY_BOOL(HasStorage, hasStorage)
132132
KEY_BOOL(ReqNewWitnessTableEntry, reqNewWitnessTableEntry)
133133
KEY_BOOL(IsABIPlaceholder, isABIPlaceholder)
134134
KEY_BOOL(IsExternal, isExternal)
135+
KEY_BOOL(HasMissingDesignatedInitializers, hasMissingDesignatedInitializers)
136+
KEY_BOOL(InheritsConvenienceInitializers, inheritsConvenienceInitializers)
135137

136138
KEY(kind)
137139

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,26 @@ public protocol DerivedProtocolRequiementChanges: RequiementChanges {}
105105

106106
public class SuperClassRemoval: C3 {}
107107

108-
public class ClassToStruct {}
108+
public class ClassToStruct {
109+
public init() {}
110+
}
111+
112+
open class ClassWithMissingDesignatedInits {
113+
internal init() {}
114+
public convenience init(x: Int) { self.init() }
115+
}
116+
117+
open class ClassWithoutMissingDesignatedInits {
118+
public init() {}
119+
public convenience init(x: Int) { self.init() }
120+
}
121+
122+
public class SubclassWithMissingDesignatedInits: ClassWithMissingDesignatedInits {
123+
}
124+
125+
public class SubclassWithoutMissingDesignatedInits: ClassWithoutMissingDesignatedInits {
126+
}
127+
109128
public protocol ProtocolToEnum {}
110129

111130
public class SuperClassChange: C7 {}

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,30 @@ public protocol DerivedProtocolRequiementChanges: RequiementChanges {}
114114

115115
public class SuperClassRemoval {}
116116

117-
public struct ClassToStruct {}
117+
public struct ClassToStruct {
118+
public init() {}
119+
}
120+
121+
open class ClassWithMissingDesignatedInits {
122+
// Remove the @_hasMissingDesignatedInitializers attribute
123+
public init() {}
124+
public convenience init(x: Int) { self.init() }
125+
}
126+
127+
open class ClassWithoutMissingDesignatedInits {
128+
// Add the @_hasMissingDesignatedInitializers attribute by adding an inaccessible
129+
// init
130+
public init() {}
131+
public convenience init(x: Int) { self.init() }
132+
internal init(y: Int) {}
133+
}
134+
135+
public class SubclassWithMissingDesignatedInits: ClassWithMissingDesignatedInits {
136+
}
137+
138+
public class SubclassWithoutMissingDesignatedInits: ClassWithoutMissingDesignatedInits {
139+
}
140+
118141
public enum ProtocolToEnum {}
119142

120143
public class SuperClassChange: C8 {}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ cake: Class C0 is a new API without @available attribute
6060
cake: Class C5 is now without @objc
6161
cake: Class C8 is a new API without @available attribute
6262
cake: Constructor C1.init(_:) is a new API without @available attribute
63+
cake: Constructor ClassWithMissingDesignatedInits.init() is a new API without @available attribute
64+
cake: Constructor SubclassWithMissingDesignatedInits.init() is a new API without @available attribute
6365
cake: Enum IceKind is now without @frozen
6466
cake: EnumElement FrozenKind.AddedCase is a new API without @available attribute
6567
cake: Func C1.foo1() is now not static
@@ -102,15 +104,17 @@ cake: Struct fixedLayoutStruct has added a conformance to an existing protocol P
102104
cake: Struct fixedLayoutStruct has removed conformance to P1
103105

104106
/* Protocol Requirement Change */
105-
cake: Accessor HasMutatingMethodClone.bar.Get() now requires new witness table entry
107+
cake: Accessor HasMutatingMethodClone.bar.Get() now requires new witness table entry
106108
cake: AssociatedType AssociatedTypePro.T1 has removed default type Swift.Int
107109
cake: AssociatedType RequiementChanges.addedTypeWithoutDefault has been added as a protocol requirement
108-
cake: Func HasMutatingMethodClone.foo() now requires new witness table entry
110+
cake: Func HasMutatingMethodClone.foo() now requires new witness table entry
109111
cake: Func RequiementChanges.addedFunc() has been added as a protocol requirement
110112
cake: Var RequiementChanges.addedVar has been added as a protocol requirement
111113

112114
/* Class Inheritance Change */
113115
cake: Class C4 has changed its super class from APINotesTest.OldType to APINotesTest.NewType
114116
cake: Class SubGenericClass has changed its super class from cake.GenericClass<cake.P1> to cake.GenericClass<cake.P2>
115117
cake: Class SuperClassRemoval has removed its super class cake.C3
118+
cake: Class SuperClassRemoval no longer inherits convenience inits from its superclass
116119
cake: Constructor AddingNewDesignatedInit.init(_:) has been added as a designated initializer to an open class
120+
cake: Constructor ClassWithMissingDesignatedInits.init() has been added as a designated initializer to an open class

test/api-digester/Outputs/Cake.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ cake: Accessor ClassWithOpenMember.property.Get() is no longer open for subclass
6464
cake: Class C4 has changed its super class from APINotesTest.OldType to APINotesTest.NewType
6565
cake: Class SubGenericClass has changed its super class from cake.GenericClass<cake.P1> to cake.GenericClass<cake.P2>
6666
cake: Class SuperClassRemoval has removed its super class cake.C3
67+
cake: Class SuperClassRemoval no longer inherits convenience inits from its superclass
6768
cake: Constructor AddingNewDesignatedInit.init(_:) has been added as a designated initializer to an open class
69+
cake: Constructor ClassWithMissingDesignatedInits.init() has been added as a designated initializer to an open class
6870
cake: Func ClassWithOpenMember.bar() is no longer open for subclassing
6971
cake: Func ClassWithOpenMember.foo() is no longer open for subclassing
7072
cake: Var ClassWithOpenMember.property is no longer open for subclassing

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@
199199
"usr": "s:4cake2C0C",
200200
"moduleName": "cake",
201201
"genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
202-
"sugared_genericSig": "<T1, T2, T3>"
202+
"sugared_genericSig": "<T1, T2, T3>",
203+
"hasMissingDesignatedInitializers": true
203204
},
204205
{
205206
"kind": "TypeDecl",
@@ -428,6 +429,8 @@
428429
"usr": "s:4cake2C1C",
429430
"moduleName": "cake",
430431
"superclassUsr": "s:4cake2C0C",
432+
"hasMissingDesignatedInitializers": true,
433+
"inheritsConvenienceInitializers": true,
431434
"superclassNames": [
432435
"cake.C0<cake.S1, cake.S1, cake.S1>"
433436
]
@@ -1330,7 +1333,8 @@
13301333
"declAttributes": [
13311334
"FixedLayout",
13321335
"UsableFromInline"
1333-
]
1336+
],
1337+
"hasMissingDesignatedInitializers": true
13341338
},
13351339
{
13361340
"kind": "TypeDecl",
@@ -1387,6 +1391,7 @@
13871391
"declKind": "Class",
13881392
"usr": "s:4cake15FutureContainerC",
13891393
"moduleName": "cake",
1394+
"hasMissingDesignatedInitializers": true,
13901395
"conformances": [
13911396
{
13921397
"kind": "Conformance",
@@ -1418,7 +1423,8 @@
14181423
"Available",
14191424
"Available",
14201425
"Available"
1421-
]
1426+
],
1427+
"hasMissingDesignatedInitializers": true
14221428
},
14231429
{
14241430
"kind": "TypeDecl",
@@ -1430,7 +1436,8 @@
14301436
"intro_swift": "5",
14311437
"declAttributes": [
14321438
"Available"
1433-
]
1439+
],
1440+
"hasMissingDesignatedInitializers": true
14341441
},
14351442
{
14361443
"kind": "TypeDecl",
@@ -1482,7 +1489,8 @@
14821489
"objc_name": "NewObjCClass",
14831490
"declAttributes": [
14841491
"ObjC"
1485-
]
1492+
],
1493+
"hasMissingDesignatedInitializers": true
14861494
},
14871495
{
14881496
"kind": "TypeDecl",

test/api-digester/Outputs/cake.json

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@
201201
"declKind": "Class",
202202
"usr": "s:4cake2C0C",
203203
"moduleName": "cake",
204-
"genericSig": "<T1, T2, T3>"
204+
"genericSig": "<T1, T2, T3>",
205+
"hasMissingDesignatedInitializers": true
205206
},
206207
{
207208
"kind": "TypeAlias",
@@ -425,6 +426,8 @@
425426
"usr": "s:4cake2C1C",
426427
"moduleName": "cake",
427428
"superclassUsr": "s:4cake2C0C",
429+
"hasMissingDesignatedInitializers": true,
430+
"inheritsConvenienceInitializers": true,
428431
"superclassNames": [
429432
"cake.C0<cake.S1, cake.S1, cake.S1>"
430433
]
@@ -1235,6 +1238,7 @@
12351238
"declKind": "Class",
12361239
"usr": "s:4cake15FutureContainerC",
12371240
"moduleName": "cake",
1241+
"hasMissingDesignatedInitializers": true,
12381242
"conformances": [
12391243
{
12401244
"kind": "Conformance",
@@ -1266,7 +1270,8 @@
12661270
"Available",
12671271
"Available",
12681272
"Available"
1269-
]
1273+
],
1274+
"hasMissingDesignatedInitializers": true
12701275
},
12711276
{
12721277
"kind": "TypeDecl",
@@ -1278,7 +1283,8 @@
12781283
"intro_swift": "5",
12791284
"declAttributes": [
12801285
"Available"
1281-
]
1286+
],
1287+
"hasMissingDesignatedInitializers": true
12821288
},
12831289
{
12841290
"kind": "TypeDecl",
@@ -1330,7 +1336,8 @@
13301336
"objc_name": "NewObjCClass",
13311337
"declAttributes": [
13321338
"ObjC"
1333-
]
1339+
],
1340+
"hasMissingDesignatedInitializers": true
13341341
},
13351342
{
13361343
"kind": "TypeDecl",

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
"Dynamic"
120120
],
121121
"superclassUsr": "c:objc(cs)NSObject",
122+
"inheritsConvenienceInitializers": true,
122123
"superclassNames": [
123124
"ObjectiveC.NSObject"
124125
],
@@ -134,6 +135,24 @@
134135
"name": "NSObjectProtocol",
135136
"printedName": "NSObjectProtocol",
136137
"usr": "c:objc(pl)NSObject"
138+
},
139+
{
140+
"kind": "Conformance",
141+
"name": "Equatable",
142+
"printedName": "Equatable",
143+
"usr": "s:SQ"
144+
},
145+
{
146+
"kind": "Conformance",
147+
"name": "Hashable",
148+
"printedName": "Hashable",
149+
"usr": "s:SH"
150+
},
151+
{
152+
"kind": "Conformance",
153+
"name": "CVarArg",
154+
"printedName": "CVarArg",
155+
"usr": "s:s7CVarArgP"
137156
}
138157
]
139158
},

test/api-digester/compare-dump.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
// RUN: %empty-directory(%t.module-cache)
55
// RUN: %swift -emit-module -o %t.mod1/cake.swiftmodule %S/Inputs/cake_baseline/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource -module-name cake
66
// RUN: %swift -emit-module -o %t.mod2/cake.swiftmodule %S/Inputs/cake_current/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -module-name cake
7-
// RUN: %api-digester -dump-sdk -module cake -o - -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -I %S/Inputs/APINotesLeft > %t.dump1.json
8-
// RUN: %api-digester -dump-sdk -module cake -o - -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod2 -I %S/Inputs/APINotesLeft > %t.dump2.json
7+
// RUN: %api-digester -dump-sdk -module cake -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -I %S/Inputs/APINotesLeft
8+
// RUN: %api-digester -dump-sdk -module cake -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod2 -I %S/Inputs/APINotesRight
99
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result
1010

1111
// RUN: %clang -E -P -x c %S/Outputs/Cake.txt -o - | sed '/^\s*$/d' > %t.expected

tools/swift-api-digester/ModuleAnalyzerNodes.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ SDKNodeTypeAlias::SDKNodeTypeAlias(SDKNodeInitInfo Info):
126126
SDKNodeDeclType::SDKNodeDeclType(SDKNodeInitInfo Info):
127127
SDKNodeDecl(Info, SDKNodeKind::DeclType), SuperclassUsr(Info.SuperclassUsr),
128128
SuperclassNames(Info.SuperclassNames),
129-
EnumRawTypeName(Info.EnumRawTypeName), IsExternal(Info.IsExternal) {}
129+
EnumRawTypeName(Info.EnumRawTypeName), IsExternal(Info.IsExternal),
130+
HasMissingDesignatedInitializers(Info.HasMissingDesignatedInitializers),
131+
InheritsConvenienceInitializers(Info.InheritsConvenienceInitializers) {}
130132

131133
SDKNodeConformance::SDKNodeConformance(SDKNodeInitInfo Info):
132134
SDKNode(Info, SDKNodeKind::Conformance),
@@ -1403,6 +1405,8 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD)
14031405
SuperclassNames.push_back(getPrintedName(Ctx, T->getCanonicalType()));
14041406
}
14051407
}
1408+
HasMissingDesignatedInitializers = CD->hasMissingDesignatedInitializers();
1409+
InheritsConvenienceInitializers = CD->inheritsSuperclassInitializers();
14061410
}
14071411

14081412
if (auto *FD = dyn_cast<FuncDecl>(VD)) {
@@ -1975,6 +1979,10 @@ void SDKNodeDeclType::jsonize(json::Output &out) {
19751979
output(out, KeyKind::KK_superclassUsr, SuperclassUsr);
19761980
output(out, KeyKind::KK_enumRawTypeName, EnumRawTypeName);
19771981
output(out, KeyKind::KK_isExternal, IsExternal);
1982+
output(out, KeyKind::KK_hasMissingDesignatedInitializers,
1983+
HasMissingDesignatedInitializers);
1984+
output(out, KeyKind::KK_inheritsConvenienceInitializers,
1985+
InheritsConvenienceInitializers);
19781986
out.mapOptional(getKeyContent(Ctx, KeyKind::KK_superclassNames).data(), SuperclassNames);
19791987
out.mapOptional(getKeyContent(Ctx, KeyKind::KK_conformances).data(), Conformances);
19801988
}

tools/swift-api-digester/ModuleAnalyzerNodes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ class SDKNodeDeclType: public SDKNodeDecl {
524524
// Check whether the type declaration is pulled from an external module so we
525525
// can incorporate extensions in the interested module.
526526
bool IsExternal;
527+
bool HasMissingDesignatedInitializers;
528+
bool InheritsConvenienceInitializers;
527529
public:
528530
SDKNodeDeclType(SDKNodeInitInfo Info);
529531
static bool classof(const SDKNode *N);
@@ -548,6 +550,13 @@ class SDKNodeDeclType: public SDKNodeDecl {
548550
return EnumRawTypeName;
549551
}
550552

553+
bool hasMissingDesignatedInitializers() const {
554+
return HasMissingDesignatedInitializers;
555+
};
556+
bool inheritsConvenienceInitializers() const {
557+
return InheritsConvenienceInitializers;
558+
};
559+
551560
Optional<SDKNodeDeclType*> getSuperclass() const;
552561

553562
/// Finding the node through all children, including the inheritted ones,

tools/swift-api-digester/ModuleDiagsConsumer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ static StringRef getCategoryName(uint32_t ID) {
7373
case LocalDiagID::super_class_changed:
7474
case LocalDiagID::no_longer_open:
7575
case LocalDiagID::desig_init_added:
76+
case LocalDiagID::added_invisible_designated_init:
77+
case LocalDiagID::not_inheriting_convenience_inits:
7678
return "/* Class Inheritance Change */";
7779
default:
7880
return StringRef();

tools/swift-api-digester/swift-api-digester.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,22 @@ void swift::ide::api::SDKNodeDeclType::diagnose(SDKNode *Right) {
789789
emitDiag(Loc, diag::super_class_changed, LSuperClass, RSuperClass);
790790
}
791791
}
792+
793+
// Check for @_hasMissingDesignatedInitializers and
794+
// @_inheritsConvenienceInitializers changes.
795+
if (isOpen() && R->isOpen()) {
796+
// It's not safe to add new, invisible designated inits to open
797+
// classes.
798+
if (!hasMissingDesignatedInitializers() &&
799+
R->hasMissingDesignatedInitializers())
800+
R->emitDiag(R->getLoc(), diag::added_invisible_designated_init);
801+
}
802+
803+
// It's not safe to stop inheriting convenience inits, it changes
804+
// the set of initializers that are available.
805+
if (inheritsConvenienceInitializers() &&
806+
!R->inheritsConvenienceInitializers())
807+
R->emitDiag(R->getLoc(), diag::not_inheriting_convenience_inits);
792808
break;
793809
}
794810
default:

0 commit comments

Comments
 (0)