mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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
This commit is contained in:
committed by
Robert Widmann
parent
511db0c90a
commit
4d731735d2
@@ -98,6 +98,10 @@ ERROR(objc_name_change,none,"%0 has ObjC name change from %1 to %2", (StringRef,
|
||||
|
||||
ERROR(desig_init_added,none,"%0 has been added as a designated initializer to an open class", (StringRef))
|
||||
|
||||
ERROR(added_invisible_designated_init,none,"%0 has new designated initializers that are not visible to clients", (StringRef))
|
||||
|
||||
ERROR(not_inheriting_convenience_inits,none,"%0 no longer inherits convenience inits from its superclass", (StringRef))
|
||||
|
||||
#ifndef DIAG_NO_UNDEF
|
||||
# if defined(DIAG)
|
||||
# undef DIAG
|
||||
|
||||
@@ -132,6 +132,8 @@ KEY_BOOL(HasStorage, hasStorage)
|
||||
KEY_BOOL(ReqNewWitnessTableEntry, reqNewWitnessTableEntry)
|
||||
KEY_BOOL(IsABIPlaceholder, isABIPlaceholder)
|
||||
KEY_BOOL(IsExternal, isExternal)
|
||||
KEY_BOOL(HasMissingDesignatedInitializers, hasMissingDesignatedInitializers)
|
||||
KEY_BOOL(InheritsConvenienceInitializers, inheritsConvenienceInitializers)
|
||||
|
||||
KEY(kind)
|
||||
|
||||
|
||||
@@ -105,7 +105,26 @@ public protocol DerivedProtocolRequiementChanges: RequiementChanges {}
|
||||
|
||||
public class SuperClassRemoval: C3 {}
|
||||
|
||||
public class ClassToStruct {}
|
||||
public class ClassToStruct {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
open class ClassWithMissingDesignatedInits {
|
||||
internal init() {}
|
||||
public convenience init(x: Int) { self.init() }
|
||||
}
|
||||
|
||||
open class ClassWithoutMissingDesignatedInits {
|
||||
public init() {}
|
||||
public convenience init(x: Int) { self.init() }
|
||||
}
|
||||
|
||||
public class SubclassWithMissingDesignatedInits: ClassWithMissingDesignatedInits {
|
||||
}
|
||||
|
||||
public class SubclassWithoutMissingDesignatedInits: ClassWithoutMissingDesignatedInits {
|
||||
}
|
||||
|
||||
public protocol ProtocolToEnum {}
|
||||
|
||||
public class SuperClassChange: C7 {}
|
||||
|
||||
@@ -114,7 +114,30 @@ public protocol DerivedProtocolRequiementChanges: RequiementChanges {}
|
||||
|
||||
public class SuperClassRemoval {}
|
||||
|
||||
public struct ClassToStruct {}
|
||||
public struct ClassToStruct {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
open class ClassWithMissingDesignatedInits {
|
||||
// Remove the @_hasMissingDesignatedInitializers attribute
|
||||
public init() {}
|
||||
public convenience init(x: Int) { self.init() }
|
||||
}
|
||||
|
||||
open class ClassWithoutMissingDesignatedInits {
|
||||
// Add the @_hasMissingDesignatedInitializers attribute by adding an inaccessible
|
||||
// init
|
||||
public init() {}
|
||||
public convenience init(x: Int) { self.init() }
|
||||
internal init(y: Int) {}
|
||||
}
|
||||
|
||||
public class SubclassWithMissingDesignatedInits: ClassWithMissingDesignatedInits {
|
||||
}
|
||||
|
||||
public class SubclassWithoutMissingDesignatedInits: ClassWithoutMissingDesignatedInits {
|
||||
}
|
||||
|
||||
public enum ProtocolToEnum {}
|
||||
|
||||
public class SuperClassChange: C8 {}
|
||||
|
||||
@@ -60,6 +60,8 @@ cake: Class C0 is a new API without @available attribute
|
||||
cake: Class C5 is now without @objc
|
||||
cake: Class C8 is a new API without @available attribute
|
||||
cake: Constructor C1.init(_:) is a new API without @available attribute
|
||||
cake: Constructor ClassWithMissingDesignatedInits.init() is a new API without @available attribute
|
||||
cake: Constructor SubclassWithMissingDesignatedInits.init() is a new API without @available attribute
|
||||
cake: Enum IceKind is now without @frozen
|
||||
cake: EnumElement FrozenKind.AddedCase is a new API without @available attribute
|
||||
cake: Func C1.foo1() is now not static
|
||||
@@ -102,10 +104,10 @@ cake: Struct fixedLayoutStruct has added a conformance to an existing protocol P
|
||||
cake: Struct fixedLayoutStruct has removed conformance to P1
|
||||
|
||||
/* Protocol Requirement Change */
|
||||
cake: Accessor HasMutatingMethodClone.bar.Get() now requires new witness table entry
|
||||
cake: Accessor HasMutatingMethodClone.bar.Get() now requires new witness table entry
|
||||
cake: AssociatedType AssociatedTypePro.T1 has removed default type Swift.Int
|
||||
cake: AssociatedType RequiementChanges.addedTypeWithoutDefault has been added as a protocol requirement
|
||||
cake: Func HasMutatingMethodClone.foo() now requires new witness table entry
|
||||
cake: Func HasMutatingMethodClone.foo() now requires new witness table entry
|
||||
cake: Func RequiementChanges.addedFunc() has been added as a protocol requirement
|
||||
cake: Var RequiementChanges.addedVar has been added as a protocol requirement
|
||||
|
||||
@@ -113,4 +115,6 @@ cake: Var RequiementChanges.addedVar has been added as a protocol requirement
|
||||
cake: Class C4 has changed its super class from APINotesTest.OldType to APINotesTest.NewType
|
||||
cake: Class SubGenericClass has changed its super class from cake.GenericClass<cake.P1> to cake.GenericClass<cake.P2>
|
||||
cake: Class SuperClassRemoval has removed its super class cake.C3
|
||||
cake: Class SuperClassRemoval no longer inherits convenience inits from its superclass
|
||||
cake: Constructor AddingNewDesignatedInit.init(_:) has been added as a designated initializer to an open class
|
||||
cake: Constructor ClassWithMissingDesignatedInits.init() has been added as a designated initializer to an open class
|
||||
|
||||
@@ -64,7 +64,9 @@ cake: Accessor ClassWithOpenMember.property.Get() is no longer open for subclass
|
||||
cake: Class C4 has changed its super class from APINotesTest.OldType to APINotesTest.NewType
|
||||
cake: Class SubGenericClass has changed its super class from cake.GenericClass<cake.P1> to cake.GenericClass<cake.P2>
|
||||
cake: Class SuperClassRemoval has removed its super class cake.C3
|
||||
cake: Class SuperClassRemoval no longer inherits convenience inits from its superclass
|
||||
cake: Constructor AddingNewDesignatedInit.init(_:) has been added as a designated initializer to an open class
|
||||
cake: Constructor ClassWithMissingDesignatedInits.init() has been added as a designated initializer to an open class
|
||||
cake: Func ClassWithOpenMember.bar() is no longer open for subclassing
|
||||
cake: Func ClassWithOpenMember.foo() is no longer open for subclassing
|
||||
cake: Var ClassWithOpenMember.property is no longer open for subclassing
|
||||
|
||||
@@ -199,7 +199,8 @@
|
||||
"usr": "s:4cake2C0C",
|
||||
"moduleName": "cake",
|
||||
"genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
|
||||
"sugared_genericSig": "<T1, T2, T3>"
|
||||
"sugared_genericSig": "<T1, T2, T3>",
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
@@ -428,6 +429,8 @@
|
||||
"usr": "s:4cake2C1C",
|
||||
"moduleName": "cake",
|
||||
"superclassUsr": "s:4cake2C0C",
|
||||
"hasMissingDesignatedInitializers": true,
|
||||
"inheritsConvenienceInitializers": true,
|
||||
"superclassNames": [
|
||||
"cake.C0<cake.S1, cake.S1, cake.S1>"
|
||||
]
|
||||
@@ -1330,7 +1333,8 @@
|
||||
"declAttributes": [
|
||||
"FixedLayout",
|
||||
"UsableFromInline"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
@@ -1387,6 +1391,7 @@
|
||||
"declKind": "Class",
|
||||
"usr": "s:4cake15FutureContainerC",
|
||||
"moduleName": "cake",
|
||||
"hasMissingDesignatedInitializers": true,
|
||||
"conformances": [
|
||||
{
|
||||
"kind": "Conformance",
|
||||
@@ -1418,7 +1423,8 @@
|
||||
"Available",
|
||||
"Available",
|
||||
"Available"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
@@ -1430,7 +1436,8 @@
|
||||
"intro_swift": "5",
|
||||
"declAttributes": [
|
||||
"Available"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
@@ -1482,7 +1489,8 @@
|
||||
"objc_name": "NewObjCClass",
|
||||
"declAttributes": [
|
||||
"ObjC"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
|
||||
@@ -201,7 +201,8 @@
|
||||
"declKind": "Class",
|
||||
"usr": "s:4cake2C0C",
|
||||
"moduleName": "cake",
|
||||
"genericSig": "<T1, T2, T3>"
|
||||
"genericSig": "<T1, T2, T3>",
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeAlias",
|
||||
@@ -425,6 +426,8 @@
|
||||
"usr": "s:4cake2C1C",
|
||||
"moduleName": "cake",
|
||||
"superclassUsr": "s:4cake2C0C",
|
||||
"hasMissingDesignatedInitializers": true,
|
||||
"inheritsConvenienceInitializers": true,
|
||||
"superclassNames": [
|
||||
"cake.C0<cake.S1, cake.S1, cake.S1>"
|
||||
]
|
||||
@@ -1235,6 +1238,7 @@
|
||||
"declKind": "Class",
|
||||
"usr": "s:4cake15FutureContainerC",
|
||||
"moduleName": "cake",
|
||||
"hasMissingDesignatedInitializers": true,
|
||||
"conformances": [
|
||||
{
|
||||
"kind": "Conformance",
|
||||
@@ -1266,7 +1270,8 @@
|
||||
"Available",
|
||||
"Available",
|
||||
"Available"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
@@ -1278,7 +1283,8 @@
|
||||
"intro_swift": "5",
|
||||
"declAttributes": [
|
||||
"Available"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
@@ -1330,7 +1336,8 @@
|
||||
"objc_name": "NewObjCClass",
|
||||
"declAttributes": [
|
||||
"ObjC"
|
||||
]
|
||||
],
|
||||
"hasMissingDesignatedInitializers": true
|
||||
},
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"Dynamic"
|
||||
],
|
||||
"superclassUsr": "c:objc(cs)NSObject",
|
||||
"inheritsConvenienceInitializers": true,
|
||||
"superclassNames": [
|
||||
"ObjectiveC.NSObject"
|
||||
],
|
||||
@@ -134,6 +135,24 @@
|
||||
"name": "NSObjectProtocol",
|
||||
"printedName": "NSObjectProtocol",
|
||||
"usr": "c:objc(pl)NSObject"
|
||||
},
|
||||
{
|
||||
"kind": "Conformance",
|
||||
"name": "Equatable",
|
||||
"printedName": "Equatable",
|
||||
"usr": "s:SQ"
|
||||
},
|
||||
{
|
||||
"kind": "Conformance",
|
||||
"name": "Hashable",
|
||||
"printedName": "Hashable",
|
||||
"usr": "s:SH"
|
||||
},
|
||||
{
|
||||
"kind": "Conformance",
|
||||
"name": "CVarArg",
|
||||
"printedName": "CVarArg",
|
||||
"usr": "s:s7CVarArgP"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
// RUN: %empty-directory(%t.module-cache)
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result
|
||||
|
||||
// RUN: %clang -E -P -x c %S/Outputs/Cake.txt -o - | sed '/^\s*$/d' > %t.expected
|
||||
|
||||
@@ -126,7 +126,9 @@ SDKNodeTypeAlias::SDKNodeTypeAlias(SDKNodeInitInfo Info):
|
||||
SDKNodeDeclType::SDKNodeDeclType(SDKNodeInitInfo Info):
|
||||
SDKNodeDecl(Info, SDKNodeKind::DeclType), SuperclassUsr(Info.SuperclassUsr),
|
||||
SuperclassNames(Info.SuperclassNames),
|
||||
EnumRawTypeName(Info.EnumRawTypeName), IsExternal(Info.IsExternal) {}
|
||||
EnumRawTypeName(Info.EnumRawTypeName), IsExternal(Info.IsExternal),
|
||||
HasMissingDesignatedInitializers(Info.HasMissingDesignatedInitializers),
|
||||
InheritsConvenienceInitializers(Info.InheritsConvenienceInitializers) {}
|
||||
|
||||
SDKNodeConformance::SDKNodeConformance(SDKNodeInitInfo Info):
|
||||
SDKNode(Info, SDKNodeKind::Conformance),
|
||||
@@ -1403,6 +1405,8 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD)
|
||||
SuperclassNames.push_back(getPrintedName(Ctx, T->getCanonicalType()));
|
||||
}
|
||||
}
|
||||
HasMissingDesignatedInitializers = CD->hasMissingDesignatedInitializers();
|
||||
InheritsConvenienceInitializers = CD->inheritsSuperclassInitializers();
|
||||
}
|
||||
|
||||
if (auto *FD = dyn_cast<FuncDecl>(VD)) {
|
||||
@@ -1975,6 +1979,10 @@ void SDKNodeDeclType::jsonize(json::Output &out) {
|
||||
output(out, KeyKind::KK_superclassUsr, SuperclassUsr);
|
||||
output(out, KeyKind::KK_enumRawTypeName, EnumRawTypeName);
|
||||
output(out, KeyKind::KK_isExternal, IsExternal);
|
||||
output(out, KeyKind::KK_hasMissingDesignatedInitializers,
|
||||
HasMissingDesignatedInitializers);
|
||||
output(out, KeyKind::KK_inheritsConvenienceInitializers,
|
||||
InheritsConvenienceInitializers);
|
||||
out.mapOptional(getKeyContent(Ctx, KeyKind::KK_superclassNames).data(), SuperclassNames);
|
||||
out.mapOptional(getKeyContent(Ctx, KeyKind::KK_conformances).data(), Conformances);
|
||||
}
|
||||
|
||||
@@ -524,6 +524,8 @@ class SDKNodeDeclType: public SDKNodeDecl {
|
||||
// Check whether the type declaration is pulled from an external module so we
|
||||
// can incorporate extensions in the interested module.
|
||||
bool IsExternal;
|
||||
bool HasMissingDesignatedInitializers;
|
||||
bool InheritsConvenienceInitializers;
|
||||
public:
|
||||
SDKNodeDeclType(SDKNodeInitInfo Info);
|
||||
static bool classof(const SDKNode *N);
|
||||
@@ -548,6 +550,13 @@ public:
|
||||
return EnumRawTypeName;
|
||||
}
|
||||
|
||||
bool hasMissingDesignatedInitializers() const {
|
||||
return HasMissingDesignatedInitializers;
|
||||
};
|
||||
bool inheritsConvenienceInitializers() const {
|
||||
return InheritsConvenienceInitializers;
|
||||
};
|
||||
|
||||
Optional<SDKNodeDeclType*> getSuperclass() const;
|
||||
|
||||
/// Finding the node through all children, including the inheritted ones,
|
||||
|
||||
@@ -73,6 +73,8 @@ static StringRef getCategoryName(uint32_t ID) {
|
||||
case LocalDiagID::super_class_changed:
|
||||
case LocalDiagID::no_longer_open:
|
||||
case LocalDiagID::desig_init_added:
|
||||
case LocalDiagID::added_invisible_designated_init:
|
||||
case LocalDiagID::not_inheriting_convenience_inits:
|
||||
return "/* Class Inheritance Change */";
|
||||
default:
|
||||
return StringRef();
|
||||
|
||||
@@ -789,6 +789,22 @@ void swift::ide::api::SDKNodeDeclType::diagnose(SDKNode *Right) {
|
||||
emitDiag(Loc, diag::super_class_changed, LSuperClass, RSuperClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for @_hasMissingDesignatedInitializers and
|
||||
// @_inheritsConvenienceInitializers changes.
|
||||
if (isOpen() && R->isOpen()) {
|
||||
// It's not safe to add new, invisible designated inits to open
|
||||
// classes.
|
||||
if (!hasMissingDesignatedInitializers() &&
|
||||
R->hasMissingDesignatedInitializers())
|
||||
R->emitDiag(R->getLoc(), diag::added_invisible_designated_init);
|
||||
}
|
||||
|
||||
// It's not safe to stop inheriting convenience inits, it changes
|
||||
// the set of initializers that are available.
|
||||
if (inheritsConvenienceInitializers() &&
|
||||
!R->inheritsConvenienceInitializers())
|
||||
R->emitDiag(R->getLoc(), diag::not_inheriting_convenience_inits);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user