Skip to content

Commit f55d3ad

Browse files
committed
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
1 parent 05bec0c commit f55d3ad

File tree

9 files changed

+53
-3
lines changed

9 files changed

+53
-3
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(type_witness_change,none,"%0 has type witness type for %1 changing from %2
9696

9797
ERROR(decl_new_witness_table_entry,none,"%0 now requires %select{|no}1 new witness table entry", (StringRef, bool))
9898

99+
ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef))
100+
99101
#ifndef DIAG_NO_UNDEF
100102
# if defined(DIAG)
101103
# undef DIAG

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ cake1: Var C1.CIIns1 changes from weak to strong
5757
cake1: Var C1.CIIns2 changes from strong to weak
5858
cake1: Var GlobalLetChangedToVar changes from let to var
5959
cake1: Var GlobalVarChangedToLet changes from var to let
60+
cake2: Accessor GlobalLetChangedToVar.Set() is a new API without @available attribute
61+
cake2: Accessor fixedLayoutStruct2.BecomeFixedBinaryOrder.Set() is a new API without @available attribute
62+
cake2: AssociatedType RequiementChanges.addedTypeWithDefault is a new API without @available attribute
63+
cake2: AssociatedType RequiementChanges.addedTypeWithoutDefault is a new API without @available attribute
64+
cake2: Class C0 is a new API without @available attribute
65+
cake2: Class C8 is a new API without @available attribute
66+
cake2: Constructor C1.init(_:) is a new API without @available attribute
67+
cake2: EnumElement FrozenKind.AddedCase is a new API without @available attribute
68+
cake2: Func RequiementChanges.addedFunc() is a new API without @available attribute
69+
cake2: Func fixedLayoutStruct.OKChange() is a new API without @available attribute
70+
cake2: Protocol P4 is a new API without @available attribute
71+
cake2: Var RequiementChanges.addedVar is a new API without @available attribute
72+
cake2: Var fixedLayoutStruct.$__lazy_storage_$_lazy_d is a new API without @available attribute
73+
cake2: Var fixedLayoutStruct.c is a new API without @available attribute
6074

6175
/* Fixed-layout Type changes */
6276
cake1: EnumElement FrozenKind.Fixed in a non-resilient type changes position from 1 to 2

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,10 @@
10351035
"moduleName": "cake",
10361036
"genericSig": "<τ_0_0 where τ_0_0 : PSuper>",
10371037
"isABIPlaceholder": true,
1038+
"intro_Macosx": "9999",
1039+
"intro_iOS": "9999",
1040+
"intro_tvOS": "9999",
1041+
"intro_watchOS": "9999",
10381042
"funcSelfKind": "NonMutating"
10391043
}
10401044
],

test/api-digester/Outputs/cake.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,10 @@
982982
"moduleName": "cake",
983983
"genericSig": "<Self where Self : PSuper>",
984984
"isABIPlaceholder": true,
985+
"intro_Macosx": "9999",
986+
"intro_iOS": "9999",
987+
"intro_tvOS": "9999",
988+
"intro_watchOS": "9999",
985989
"funcSelfKind": "NonMutating"
986990
}
987991
],

test/api-digester/Outputs/stability-stdlib-abi.swift.expected

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
// The init(signOf:magnitudeOf:) blames are false positives. They are not new APIs.
2+
Constructor Double.init(signOf:magnitudeOf:) is a new API without @available attribute
3+
Constructor Float.init(signOf:magnitudeOf:) is a new API without @available attribute
4+
Constructor Float80.init(signOf:magnitudeOf:) is a new API without @available attribute
5+
6+
Constructor __RawDictionaryStorage.init(coder:) is a new API without @available attribute
7+
Constructor __RawSetStorage.init(coder:) is a new API without @available attribute
8+
Constructor __SwiftNativeNSData.init(coder:) is a new API without @available attribute
9+
Constructor __SwiftNativeNSDictionary.init(coder:) is a new API without @available attribute
10+
Constructor __SwiftNativeNSSet.init(coder:) is a new API without @available attribute
11+
112
Func _cos(_:) has been removed
213
Func _exp(_:) has been removed
314
Func _exp2(_:) has been removed

tools/swift-api-digester/ModuleAnalyzerNodes.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,25 +1145,29 @@ static bool isABIPlaceholderRecursive(Decl *D) {
11451145
}
11461146

11471147
StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) {
1148+
if (!D)
1149+
return StringRef();
11481150
for (auto *ATT: D->getAttrs()) {
11491151
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
11501152
if (AVA->Platform == Kind && AVA->Introduced) {
11511153
return buffer(AVA->Introduced->getAsString());
11521154
}
11531155
}
11541156
}
1155-
return StringRef();
1157+
return getPlatformIntroVersion(D->getDeclContext()->getAsDecl(), Kind);
11561158
}
11571159

11581160
StringRef SDKContext::getLanguageIntroVersion(Decl *D) {
1161+
if (!D)
1162+
return StringRef();
11591163
for (auto *ATT: D->getAttrs()) {
11601164
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
11611165
if (AVA->isLanguageVersionSpecific() && AVA->Introduced) {
11621166
return buffer(AVA->Introduced->getAsString());
11631167
}
11641168
}
11651169
}
1166-
return StringRef();
1170+
return getLanguageIntroVersion(D->getDeclContext()->getAsDecl());
11671171
}
11681172

11691173
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Type Ty, TypeInitInfo Info) :

tools/swift-api-digester/ModuleAnalyzerNodes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ struct PlatformIntroVersion {
293293
StringRef tvos;
294294
StringRef watchos;
295295
StringRef swift;
296+
bool hasOSAvailability() const {
297+
return !macos.empty() || !ios.empty() || !tvos.empty() || !watchos.empty();
298+
}
296299
};
297300

298301
class SDKNodeDecl: public SDKNode {
@@ -347,6 +350,7 @@ class SDKNodeDecl: public SDKNode {
347350
StringRef getScreenInfo() const;
348351
bool hasFixedBinaryOrder() const { return FixedBinaryOrder.hasValue(); }
349352
uint8_t getFixedBinaryOrder() const { return *FixedBinaryOrder; }
353+
PlatformIntroVersion getIntroducingVersion() const { return introVersions; }
350354
virtual void jsonize(json::Output &Out) override;
351355
virtual void diagnose(SDKNode *Right) override;
352356

tools/swift-api-digester/ModuleDiagsConsumer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static StringRef getCategoryName(uint32_t ID) {
4444
case LocalDiagID::decl_new_attr:
4545
case LocalDiagID::var_let_changed:
4646
case LocalDiagID::func_self_access_change:
47+
case LocalDiagID::new_decl_without_intro:
4748
return "/* Decl Attribute changes */";
4849
case LocalDiagID::default_arg_removed:
4950
case LocalDiagID::decl_type_change:

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,13 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass {
10031003
if (D->hasFixedBinaryOrder()) {
10041004
D->emitDiag(diag::decl_added);
10051005
}
1006+
// Diagnose the missing of @available attributes.
1007+
// Decls with @_alwaysEmitIntoClient aren't required to have an
1008+
// @available attribute.
1009+
if (!D->getIntroducingVersion().hasOSAvailability() &&
1010+
!D->hasDeclAttribute(DeclAttrKind::DAK_AlwaysEmitIntoClient)) {
1011+
D->emitDiag(diag::new_decl_without_intro);
1012+
}
10061013
}
10071014
}
10081015
// Complain about added protocol requirements
@@ -1038,7 +1045,6 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass {
10381045
}
10391046
}
10401047
}
1041-
10421048
return;
10431049
case NodeMatchReason::Removed:
10441050
assert(!Right);

0 commit comments

Comments
 (0)