API checker: only diagnose adding enum cases to exhaustive enums

Adding new cases to a non-exhaustive enum type isn't source-breaking
since it only triggers a warning.

rdar://63464929
This commit is contained in:
Xi Ge
2020-05-23 15:43:07 -07:00
parent bcdebc6426
commit c5730beb42
9 changed files with 26 additions and 3 deletions

View File

@@ -132,6 +132,7 @@ KEY_BOOL(HasStorage, hasStorage)
KEY_BOOL(ReqNewWitnessTableEntry, reqNewWitnessTableEntry)
KEY_BOOL(IsABIPlaceholder, isABIPlaceholder)
KEY_BOOL(IsExternal, isExternal)
KEY_BOOL(IsEnumExhaustive, isEnumExhaustive)
KEY_BOOL(HasMissingDesignatedInitializers, hasMissingDesignatedInitializers)
KEY_BOOL(InheritsConvenienceInitializers, inheritsConvenienceInitializers)

View File

@@ -40,6 +40,9 @@ public struct C6 {}
@frozen
public enum IceKind {}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
public enum FutureKind {}
public protocol P1 {}
public protocol P2 {}

View File

@@ -40,6 +40,11 @@ public struct C6 {}
public enum IceKind {}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
public enum FutureKind {
case FineToAdd
}
public protocol P1 {}
public protocol P2 {}

View File

@@ -615,6 +615,7 @@
"usr": "s:4cake6NumberO",
"moduleName": "cake",
"enumRawTypeName": "Int",
"isEnumExhaustive": true,
"conformances": [
{
"kind": "Conformance",

View File

@@ -635,6 +635,7 @@
"usr": "s:4cake6NumberO",
"moduleName": "cake",
"enumRawTypeName": "Int",
"isEnumExhaustive": true,
"conformances": [
{
"kind": "Conformance",

View File

@@ -1,4 +1,4 @@
// REQUIRES: macosx
// REQUIRES: OS=macosx
// RUN: %empty-directory(%t.mod)
// RUN: %empty-directory(%t.sdk)
// RUN: %empty-directory(%t.module-cache)

View File

@@ -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),
IsEnumExhaustive(Info.IsEnumExhaustive),
HasMissingDesignatedInitializers(Info.HasMissingDesignatedInitializers),
InheritsConvenienceInitializers(Info.InheritsConvenienceInitializers) {}
@@ -1426,6 +1428,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD)
// Get enum raw type name if this is an enum.
if (auto *ED = dyn_cast<EnumDecl>(VD)) {
IsEnumExhaustive = ED->isFormallyExhaustive(nullptr);
if (auto RT = ED->getRawType()) {
if (auto *D = RT->getNominalOrBoundGenericNominal()) {
EnumRawTypeName = D->getName().str();
@@ -1981,6 +1984,7 @@ 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_isEnumExhaustive, IsEnumExhaustive);
output(out, KeyKind::KK_hasMissingDesignatedInitializers,
HasMissingDesignatedInitializers);
output(out, KeyKind::KK_inheritsConvenienceInitializers,

View File

@@ -524,6 +524,7 @@ 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 IsEnumExhaustive;
bool HasMissingDesignatedInitializers;
bool InheritsConvenienceInitializers;
public:
@@ -550,6 +551,11 @@ public:
return EnumRawTypeName;
}
bool isEnumExhaustive() const {
assert(isEnum());
return IsEnumExhaustive;
}
bool hasMissingDesignatedInitializers() const {
return HasMissingDesignatedInitializers;
};

View File

@@ -1216,10 +1216,12 @@ public:
if (!Ctx.checkingABI()) {
if (auto *Var = dyn_cast<SDKNodeDeclVar>(Right)) {
if (Var->getDeclKind() == DeclKind::EnumElement) {
if (Var->getParent()->getAs<SDKNodeDeclType>()->isEnumExhaustive()) {
Var->emitDiag(Var->getLoc(), diag::enum_case_added);
}
}
}
}
return;
case NodeMatchReason::Removed:
assert(!Right);