ABI checker: diagnose the missing of @available attributes for added ABIs

New ABIs should have an @available attribute to describe the introducing
version. This patch teaches the tool to diagnose its missing.

Decls with @_AlwaysEmitIntoClient are excluded from the blaming lists since
they are essentially available all the time.

rdar://51089418
This commit is contained in:
Xi Ge
2019-05-28 16:04:24 -07:00
parent 05bec0c3e3
commit f55d3ad029
9 changed files with 53 additions and 3 deletions

View File

@@ -96,6 +96,8 @@ ERROR(type_witness_change,none,"%0 has type witness type for %1 changing from %2
ERROR(decl_new_witness_table_entry,none,"%0 now requires %select{|no}1 new witness table entry", (StringRef, bool))
ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef))
#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG

View File

@@ -57,6 +57,20 @@ cake1: Var C1.CIIns1 changes from weak to strong
cake1: Var C1.CIIns2 changes from strong to weak
cake1: Var GlobalLetChangedToVar changes from let to var
cake1: Var GlobalVarChangedToLet changes from var to let
cake2: Accessor GlobalLetChangedToVar.Set() is a new API without @available attribute
cake2: Accessor fixedLayoutStruct2.BecomeFixedBinaryOrder.Set() is a new API without @available attribute
cake2: AssociatedType RequiementChanges.addedTypeWithDefault is a new API without @available attribute
cake2: AssociatedType RequiementChanges.addedTypeWithoutDefault is a new API without @available attribute
cake2: Class C0 is a new API without @available attribute
cake2: Class C8 is a new API without @available attribute
cake2: Constructor C1.init(_:) is a new API without @available attribute
cake2: EnumElement FrozenKind.AddedCase is a new API without @available attribute
cake2: Func RequiementChanges.addedFunc() is a new API without @available attribute
cake2: Func fixedLayoutStruct.OKChange() is a new API without @available attribute
cake2: Protocol P4 is a new API without @available attribute
cake2: Var RequiementChanges.addedVar is a new API without @available attribute
cake2: Var fixedLayoutStruct.$__lazy_storage_$_lazy_d is a new API without @available attribute
cake2: Var fixedLayoutStruct.c is a new API without @available attribute
/* Fixed-layout Type changes */
cake1: EnumElement FrozenKind.Fixed in a non-resilient type changes position from 1 to 2

View File

@@ -1035,6 +1035,10 @@
"moduleName": "cake",
"genericSig": "<τ_0_0 where τ_0_0 : PSuper>",
"isABIPlaceholder": true,
"intro_Macosx": "9999",
"intro_iOS": "9999",
"intro_tvOS": "9999",
"intro_watchOS": "9999",
"funcSelfKind": "NonMutating"
}
],

View File

@@ -982,6 +982,10 @@
"moduleName": "cake",
"genericSig": "<Self where Self : PSuper>",
"isABIPlaceholder": true,
"intro_Macosx": "9999",
"intro_iOS": "9999",
"intro_tvOS": "9999",
"intro_watchOS": "9999",
"funcSelfKind": "NonMutating"
}
],

View File

@@ -1,3 +1,14 @@
// The init(signOf:magnitudeOf:) blames are false positives. They are not new APIs.
Constructor Double.init(signOf:magnitudeOf:) is a new API without @available attribute
Constructor Float.init(signOf:magnitudeOf:) is a new API without @available attribute
Constructor Float80.init(signOf:magnitudeOf:) is a new API without @available attribute
Constructor __RawDictionaryStorage.init(coder:) is a new API without @available attribute
Constructor __RawSetStorage.init(coder:) is a new API without @available attribute
Constructor __SwiftNativeNSData.init(coder:) is a new API without @available attribute
Constructor __SwiftNativeNSDictionary.init(coder:) is a new API without @available attribute
Constructor __SwiftNativeNSSet.init(coder:) is a new API without @available attribute
Func _cos(_:) has been removed
Func _exp(_:) has been removed
Func _exp2(_:) has been removed

View File

@@ -1145,6 +1145,8 @@ static bool isABIPlaceholderRecursive(Decl *D) {
}
StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) {
if (!D)
return StringRef();
for (auto *ATT: D->getAttrs()) {
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
if (AVA->Platform == Kind && AVA->Introduced) {
@@ -1152,10 +1154,12 @@ StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) {
}
}
}
return StringRef();
return getPlatformIntroVersion(D->getDeclContext()->getAsDecl(), Kind);
}
StringRef SDKContext::getLanguageIntroVersion(Decl *D) {
if (!D)
return StringRef();
for (auto *ATT: D->getAttrs()) {
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
if (AVA->isLanguageVersionSpecific() && AVA->Introduced) {
@@ -1163,7 +1167,7 @@ StringRef SDKContext::getLanguageIntroVersion(Decl *D) {
}
}
}
return StringRef();
return getLanguageIntroVersion(D->getDeclContext()->getAsDecl());
}
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Type Ty, TypeInitInfo Info) :

View File

@@ -293,6 +293,9 @@ struct PlatformIntroVersion {
StringRef tvos;
StringRef watchos;
StringRef swift;
bool hasOSAvailability() const {
return !macos.empty() || !ios.empty() || !tvos.empty() || !watchos.empty();
}
};
class SDKNodeDecl: public SDKNode {
@@ -347,6 +350,7 @@ public:
StringRef getScreenInfo() const;
bool hasFixedBinaryOrder() const { return FixedBinaryOrder.hasValue(); }
uint8_t getFixedBinaryOrder() const { return *FixedBinaryOrder; }
PlatformIntroVersion getIntroducingVersion() const { return introVersions; }
virtual void jsonize(json::Output &Out) override;
virtual void diagnose(SDKNode *Right) override;

View File

@@ -44,6 +44,7 @@ static StringRef getCategoryName(uint32_t ID) {
case LocalDiagID::decl_new_attr:
case LocalDiagID::var_let_changed:
case LocalDiagID::func_self_access_change:
case LocalDiagID::new_decl_without_intro:
return "/* Decl Attribute changes */";
case LocalDiagID::default_arg_removed:
case LocalDiagID::decl_type_change:

View File

@@ -1003,6 +1003,13 @@ public:
if (D->hasFixedBinaryOrder()) {
D->emitDiag(diag::decl_added);
}
// Diagnose the missing of @available attributes.
// Decls with @_alwaysEmitIntoClient aren't required to have an
// @available attribute.
if (!D->getIntroducingVersion().hasOSAvailability() &&
!D->hasDeclAttribute(DeclAttrKind::DAK_AlwaysEmitIntoClient)) {
D->emitDiag(diag::new_decl_without_intro);
}
}
}
// Complain about added protocol requirements
@@ -1038,7 +1045,6 @@ public:
}
}
}
return;
case NodeMatchReason::Removed:
assert(!Right);