Skip to content

Commit bf9c330

Browse files
committed
Modify diagnostics to suggest updating existing available attribute
1 parent bdc6fc6 commit bf9c330

11 files changed

+158
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6725,6 +6725,9 @@ ERROR(availability_variadic_type_only_version_newer, none,
67256725
NOTE(availability_guard_with_version_check, none,
67266726
"add 'if #available' version check", ())
67276727

6728+
NOTE(availability_update_attribute, none,
6729+
"update @available attribute for %0 from '%1' to '%2' to meet the requirements of '%3'", (StringRef, StringRef, StringRef, StringRef))
6730+
67286731
NOTE(availability_add_attribute, none,
67296732
"add @available attribute to enclosing %0", (DescriptiveDeclKind))
67306733
FIXIT(insert_available_attr,

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,8 +1843,26 @@ static void fixAvailabilityForDecl(SourceRange ReferenceRange, const Decl *D,
18431843
if (TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(D).has_value())
18441844
return;
18451845

1846-
if (getActiveAvailableAttribute(D, Context)) {
1847-
// For QoI, in future should emit a fixit to update the existing attribute.
1846+
if (auto Attr = getActiveAvailableAttribute(D, Context)) {
1847+
// Check if the `range` of the attribute `Attr` overlaps with its
1848+
// `IntroducedRange`, which can be from a macro or the minimum version
1849+
// supported by the compiler, etc. If there's no explicit introduction range
1850+
// marked in the code, skip the update logic and return immediately.
1851+
if (!Attr->getRange().isValid() ||
1852+
!Attr->getRange().overlaps(Attr->IntroducedRange)) {
1853+
return;
1854+
}
1855+
1856+
auto Version = Attr->Introduced->getAsString();
1857+
auto Required = RequiredRange.getLowerEndpoint().getAsString();
1858+
auto ReferenceName =
1859+
Context.SourceMgr
1860+
.extractText(Lexer::getCharSourceRangeFromSourceRange(
1861+
Context.SourceMgr, ReferenceRange))
1862+
.str();
1863+
D->diagnose(diag::availability_update_attribute, Attr->platformString(),
1864+
Version, Required, ReferenceName)
1865+
.fixItReplace(Attr->IntroducedRange, Required);
18481866
return;
18491867
}
18501868

test/Sema/api-availability-only.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public struct S {}
88

99
@available(macOS 10.51, *)
1010
public func newFunc() {
11+
// expected-note @-1 {{update @available attribute for macOS from '10.51' to '10.52' to meet the requirements of 'S'}} {{9:18-23=10.52}}
1112
_ = S() // expected-error {{'S' is only available in}}
1213
// expected-note @-1 {{add 'if #available' version check}}
1314
}

test/Sema/availability_swiftui.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ class AnyColorBox: LessAvailable {} // Ok, exception specifically for AnyColorBo
1313
@available(macOS 10.15, *)
1414
@usableFromInline
1515
class OtherClass: LessAvailable {} // expected-error {{'LessAvailable' is only available in macOS 11 or newer; clients of 'SwiftUI' may have a lower deployment target}}
16+
// expected-note @-1 {{update @available attribute for macOS from '10.15' to '11' to meet the requirements of 'LessAvailable'}} {{13:18-23=11}}

test/Sema/availability_versions.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func functionWithoutAvailability() {
4242
// Functions with annotations should refine their bodies.
4343
@available(OSX, introduced: 10.51)
4444
func functionAvailableOn10_51() {
45+
// expected-note@-1 {{update @available attribute for macOS from '10.51' to '10.52' to meet the requirements of 'globalFuncAvailableOn10_52'}} {{43:29-34=10.52}}
4546
let _: Int = globalFuncAvailableOn10_9()
4647
let _: Int = globalFuncAvailableOn10_51()
4748

@@ -324,10 +325,11 @@ class ClassWithPotentiallyUnavailableProperties {
324325

325326
@available(OSX, introduced: 10.9)
326327
var availableOn10_9Computed: Int {
328+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'availableOn10_51Stored'}} {{326:31-35=10.51}}
327329
get {
328330
let _: Int = availableOn10_51Stored // expected-error {{'availableOn10_51Stored' is only available in macOS 10.51 or newer}}
329331
// expected-note@-1 {{add 'if #available' version check}}
330-
332+
331333
if #available(OSX 10.51, *) {
332334
let _: Int = availableOn10_51Stored
333335
}
@@ -406,6 +408,7 @@ class ClassWithPotentiallyUnavailableProperties {
406408

407409
@available(OSX, introduced: 10.51)
408410
class ClassWithReferencesInInitializers {
411+
// expected-note@-1 2 {{update @available attribute for macOS from '10.51' to '10.52' to meet the requirements of 'globalFuncAvailableOn10_52'}} {{409:29-34=10.52}}
409412
var propWithInitializer10_51: Int = globalFuncAvailableOn10_51()
410413

411414
var propWithInitializer10_52: Int = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
@@ -522,6 +525,8 @@ enum EnumIntroducedOn10_52 {
522525

523526
@available(OSX, introduced: 10.51)
524527
enum CompassPoint {
528+
// expected-note@-1 3 {{update @available attribute for macOS from '10.51' to '10.52' to meet the requirements of 'EnumIntroducedOn10_52'}} {{526:29-34=10.52}}
529+
525530
case North
526531
case South
527532
case East
@@ -542,7 +547,7 @@ enum CompassPoint {
542547
case WithPotentiallyUnavailablePayload(p : EnumIntroducedOn10_52) // expected-error {{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}
543548

544549
case WithPotentiallyUnavailablePayload1(p : EnumIntroducedOn10_52), WithPotentiallyUnavailablePayload2(p : EnumIntroducedOn10_52) // expected-error 2{{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}
545-
550+
546551
@available(OSX, unavailable)
547552
case WithPotentiallyUnavailablePayload3(p : EnumIntroducedOn10_52)
548553
}
@@ -876,20 +881,21 @@ class SubWithLargerMemberAvailability : SuperWithLimitedMemberAvailability {
876881
// expected-note@-1 2{{add @available attribute to enclosing class}}
877882
@available(OSX, introduced: 10.9)
878883
override func someMethod() {
884+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'someMethod'}} {{882:31-35=10.51}}
879885
super.someMethod() // expected-error {{'someMethod()' is only available in macOS 10.51 or newer}}
880886
// expected-note@-1 {{add 'if #available' version check}}
881-
887+
882888
if #available(OSX 10.51, *) {
883889
super.someMethod()
884890
}
885891
}
886892

887893
@available(OSX, introduced: 10.9)
888894
override var someProperty: Int {
889-
get {
895+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'someProperty'}} {{893:31-35=10.51}}
896+
get {
890897
let _ = super.someProperty // expected-error {{'someProperty' is only available in macOS 10.51 or newer}}
891-
// expected-note@-1 {{add 'if #available' version check}}
892-
898+
// expected-note@-1 {{add 'if #available' version check}}
893899
if #available(OSX 10.51, *) {
894900
let _ = super.someProperty
895901
}
@@ -961,6 +967,7 @@ protocol ProtocolAvailableOn10_51 {
961967

962968
@available(OSX, introduced: 10.9)
963969
protocol ProtocolAvailableOn10_9InheritingFromProtocolAvailableOn10_51 : ProtocolAvailableOn10_51 { // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
970+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'ProtocolAvailableOn10_51'}} {{968:29-33=10.51}}
964971
}
965972

966973
@available(OSX, introduced: 10.51)
@@ -973,6 +980,7 @@ protocol UnavailableProtocolInheritingFromProtocolAvailableOn10_51 : ProtocolAva
973980

974981
@available(OSX, introduced: 10.9)
975982
class SubclassAvailableOn10_9OfClassAvailableOn10_51 : ClassAvailableOn10_51 { // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
983+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'ClassAvailableOn10_51'}} {{981:29-33=10.51}}
976984
}
977985

978986
@available(OSX, unavailable)
@@ -997,12 +1005,14 @@ func castToPotentiallyUnavailableProtocol() {
9971005

9981006
@available(OSX, introduced: 10.9)
9991007
class SubclassAvailableOn10_9OfClassAvailableOn10_51AlsoAdoptingProtocolAvailableOn10_51 : ClassAvailableOn10_51, ProtocolAvailableOn10_51 { // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
1008+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'ClassAvailableOn10_51'}} {{1006:29-33=10.51}}
10001009
}
10011010

10021011
class SomeGenericClass<T> { }
10031012

10041013
@available(OSX, introduced: 10.9)
10051014
class SubclassAvailableOn10_9OfSomeGenericClassOfProtocolAvailableOn10_51 : SomeGenericClass<ProtocolAvailableOn10_51> { // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
1015+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'ProtocolAvailableOn10_51'}} {{1013:29-33=10.51}}
10061016
}
10071017

10081018
@available(OSX, unavailable)
@@ -1049,6 +1059,7 @@ extension ClassAvailableOn10_51 { }
10491059

10501060
@available(OSX, introduced: 10.51)
10511061
extension ClassAvailableOn10_51 {
1062+
// expected-note@-1 {{update @available attribute for macOS from '10.51' to '10.52' to meet the requirements of 'globalFuncAvailableOn10_52'}} {{1060:29-34=10.52}}
10521063
func m() {
10531064
// expected-note@-1 {{add @available attribute to enclosing instance method}}
10541065
let _ = globalFuncAvailableOn10_51()
@@ -1653,6 +1664,7 @@ class ClassWithShortFormAvailableOn10_54 {
16531664

16541665
@available(OSX 10.9, *)
16551666
func funcWithShortFormAvailableOn10_9() {
1667+
// expected-note@-1 {{update @available attribute for macOS from '10.9' to '10.51' to meet the requirements of 'ClassWithShortFormAvailableOn10_51'}} {{1665:16-20=10.51}}
16561668
let _ = ClassWithShortFormAvailableOn10_51() // expected-error {{'ClassWithShortFormAvailableOn10_51' is only available in macOS 10.51 or newer}}
16571669
// expected-note@-1 {{add 'if #available' version check}}
16581670
}
@@ -1685,6 +1697,7 @@ func funcWithMultipleShortFormAnnotationsForDifferentPlatforms() {
16851697
@available(OSX 10.53, *)
16861698
@available(OSX 10.52, *)
16871699
func funcWithMultipleShortFormAnnotationsForTheSamePlatform() {
1700+
// expected-note@-1 {{update @available attribute for macOS from '10.52' to '10.54' to meet the requirements of 'ClassWithShortFormAvailableOn10_54'}} {{1698:16-21=10.54}}
16881701
let _ = ClassWithShortFormAvailableOn10_53()
16891702

16901703
let _ = ClassWithShortFormAvailableOn10_54() // expected-error {{'ClassWithShortFormAvailableOn10_54' is only available in macOS 10.54 or newer}}

test/Sema/availability_versions_multi.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ let ignored3: Int = globalAvailableOn99_52 // expected-error {{'globalAvailableO
2525

2626
@available(OSX, introduced: 99.51)
2727
func useFromOtherOn99_51() {
28+
// expected-note@-1 {{update @available attribute for macOS from '99.51' to '99.52' to meet the requirements of 'returns99_52Introduced99_52'}} {{26:29-34=99.52}}
29+
// expected-note@-2 {{update @available attribute for macOS from '99.51' to '99.52' to meet the requirements of 'OtherIntroduced99_52'}} {{26:29-34=99.52}}
30+
// expected-note@-3 {{update @available attribute for macOS from '99.51' to '99.52' to meet the requirements of 'extensionMethodOnOtherIntroduced99_51AvailableOn99_52'}} {{26:29-34=99.52}}
31+
// expected-note@-4 {{update @available attribute for macOS from '99.51' to '99.52' to meet the requirements of 'NestedIntroduced99_52'}} {{26:29-34=99.52}}
32+
2833
// This will trigger validation of OtherIntroduced99_51 in
2934
// in availability_multi_other.swift
3035
let o99_51 = OtherIntroduced99_51()
@@ -49,6 +54,7 @@ func useFromOtherOn99_51() {
4954

5055
@available(OSX, introduced: 99.52)
5156
func useFromOtherOn99_52() {
57+
// expected-note@-1 {{update @available attribute for macOS from '99.52' to '99.53' to meet the requirements of 'returns99_53'}} {{55:29-34=99.53}}
5258
_ = OtherIntroduced99_52()
5359

5460
let n99_52 = OtherIntroduced99_51.NestedIntroduced99_52()

test/attr/ApplicationMain/attr_main_struct_available_future.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
@main // expected-error {{'main()' is only available in macOS 10.99 or newer}}
66
@available(OSX 10.0, *)
7-
struct EntryPoint {
7+
struct EntryPoint { // expected-note {{update @available attribute for macOS from '10.0' to '10.99' to meet the requirements of '@main'}} {{6:16-20=10.99}}
88
@available(OSX 10.99, *)
99
static func main() {
1010
}

test/attr/attr_availability_osx.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ extension TestStruct {
115115
}
116116

117117
@available(macOS 10.11, *)
118-
func testMemberAvailability() {
118+
func testMemberAvailability() { // expected-note {{update @available attribute for macOS from '10.11' to '10.12' to meet the requirements of 'doFourthThing'}} {{117:18-23=10.12}}
119119
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}
120120
TestStruct().doAnotherThing() // expected-error {{'doAnotherThing()' is unavailable}}
121121
TestStruct().doThirdThing() // expected-error {{'doThirdThing()' is unavailable}}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %swift -typecheck -verify -parse-stdlib -module-name Swift -target x86_64-apple-macosx10.10 %s
2+
3+
@available(SwiftStdlib 5.1, *)
4+
func FooForDefineAvailability() {}
5+
6+
@available(SwiftStdlib 5.0, *)
7+
func FooForDefineAvailabilityTest() {
8+
FooForDefineAvailability()
9+
// expected-error@-1 {{'FooForDefineAvailability()' is only available in macOS 10.15 or newer}}
10+
// expected-note@-2 {{add 'if #available' version check}}
11+
}
12+
13+
@available(*, unavailable)
14+
func FooForUnavailable() {} // expected-note {{'FooForUnavailable()' has been explicitly marked unavailable here}}
15+
16+
func FooForUnavailableTest() {
17+
FooForUnavailable()
18+
// expected-error@-1 {{'FooForUnavailable()' is unavailable}}
19+
}
20+
21+
@available(macOS, introduced: 10.15)
22+
func FooForAvailability() {}
23+
24+
@available(macOS, introduced: 10.10)
25+
func FooForAvailabilityTest() {
26+
// expected-note@-1 {{update @available attribute for macOS from '10.10' to '10.15' to meet the requirements of 'FooForAvailability'}} {{24:31-36=10.15}}
27+
FooForAvailability()
28+
// expected-error@-1 {{'FooForAvailability()' is only available in macOS 10.15 or newer}}
29+
// expected-note@-2 {{add 'if #available' version check}}
30+
}
31+
32+
@available(macOS 10.15, iOS 13, *)
33+
func FooForAvailability2() {
34+
}
35+
36+
@available(macOS 10.10, *)
37+
func FooForAvailability2Test() {
38+
// expected-note@-1 {{update @available attribute for macOS from '10.10' to '10.15' to meet the requirements of 'FooForAvailability2'}} {{36:18-23=10.15}}
39+
FooForAvailability2()
40+
// expected-error@-1 {{'FooForAvailability2()' is only available in macOS 10.15 or newer}}
41+
// expected-note@-2 {{add 'if #available' version check}}
42+
}
43+
44+
@available(macOS 10.15, *)
45+
func FooForUnavailable2() {}
46+
47+
@available(macOS, unavailable)
48+
func FooForUnavailable2Test() {
49+
FooForUnavailable2()
50+
// expected-error@-1 {{'FooForUnavailable2()' is only available in macOS 10.15 or newer}}
51+
// expected-note@-2 {{add 'if #available' version check}}
52+
}
53+
54+
@available(macOS 10.15, *)
55+
func FooForDeprecated() {}
56+
57+
@available(macOS, deprecated: 12)
58+
func FooForDeprecatedTest() {
59+
FooForDeprecated()
60+
// expected-error@-1 {{'FooForDeprecated()' is only available in macOS 10.15 or newer}}
61+
// expected-note@-2 {{add 'if #available' version check}}
62+
}
63+
64+
@available(*, deprecated)
65+
func FooForDeprecatedTest2() {
66+
FooForDeprecated()
67+
// expected-error@-1 {{'FooForDeprecated()' is only available in macOS 10.15 or newer}}
68+
// expected-note@-2 {{add 'if #available' version check}}
69+
}

0 commit comments

Comments
 (0)