Skip to content

Commit

Permalink
Modify diagnostics to suggest updating existing available attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
kongkaikai committed Mar 23, 2024
1 parent 54c1e46 commit 765b2ec
Show file tree
Hide file tree
Showing 12 changed files with 122 additions and 13 deletions.
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -6649,6 +6649,9 @@ ERROR(availability_variadic_type_only_version_newer, none,
NOTE(availability_guard_with_version_check, none,
"add 'if #available' version check", ())

NOTE(update_availability_attribute, none,
"change the @available attribute of the %0 on %1 from %2 to %3", (DescriptiveDeclKind, StringRef, StringRef, StringRef))

NOTE(availability_add_attribute, none,
"add @available attribute to enclosing %0", (DescriptiveDeclKind))
FIXIT(insert_available_attr,
Expand Down
22 changes: 17 additions & 5 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1821,18 +1821,30 @@ static void fixAvailabilityForDecl(SourceRange ReferenceRange, const Decl *D,
if (TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(D).has_value())
return;

if (getActiveAvailableAttribute(D, Context)) {
// For QoI, in future should emit a fixit to update the existing attribute.
return;
}

// For some declarations (variables, enum elements), the location in concrete
// syntax to suggest the Fix-It may differ from the declaration to which
// we attach availability attributes in the abstract syntax tree during
// parsing.
const Decl *ConcDecl = concreteSyntaxDeclForAvailableAttribute(D);

DescriptiveDeclKind KindForDiagnostic = ConcDecl->getDescriptiveKind();

if (auto Attr = getActiveAvailableAttribute(D, Context)) {
if (Attr->isUnconditionallyUnavailable()) {
return;
}
SourceManager &SM = Context.SourceMgr;
auto Version = SM.extractText(Lexer::getCharSourceRangeFromSourceRange(
SM, Attr->IntroducedRange))
.str();
auto Required = RequiredRange.getLowerEndpoint().getAsString();
Context.Diags
.diagnose(ReferenceRange.Start, diag::update_availability_attribute,
KindForDiagnostic, Attr->platformString(), Version, Required)
.fixItReplace(Attr->IntroducedRange, Required);
return;
}

SourceLoc InsertLoc;

// To avoid exposing the pattern binding declaration to the user, get the
Expand Down
2 changes: 2 additions & 0 deletions test/Concurrency/sendable_checking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func testCV(

acceptCV(ns3) // expected-warning {{conformance of 'NS3' to 'Sendable' is only available in macOS 11.0 or newer}}
// expected-note @-1 {{add 'if #available' version check}}
// expected-note @-2 {{change the @available attribute of the global function on macOS from 10.15 to 11.0}}

acceptCV(ns4) // expected-complete-and-tns-warning {{type 'NS4' does not conform to the 'Sendable' protocol}}

Expand All @@ -71,6 +72,7 @@ func testCV(
acceptCV(ns2) // expected-warning{{type 'NS2' does not conform to the 'Sendable' protocol}}
acceptCV(ns3) // expected-warning{{conformance of 'NS3' to 'Sendable' is only available in macOS 11.0 or newer}}
// expected-note@-1{{add 'if #available' version check}}
// expected-note @-2 {{change the @available attribute of the global function on macOS from 10.15 to 11.0}}
acceptCV(ns4) // expected-warning{{type 'NS4' does not conform to the 'Sendable' protocol}}
acceptCV(fn) // expected-warning{{type '() -> Void' does not conform to the 'Sendable' protocol}}
// expected-note@-1{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
Expand Down
1 change: 1 addition & 0 deletions test/Sema/api-availability-only.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ public struct S {}
public func newFunc() {
_ = S() // expected-error {{'S' is only available in}}
// expected-note @-1 {{add 'if #available' version check}}
// expected-note @-2 {{change the @available attribute of the global function on macOS from 10.51 to 10.52}} {{9:18-23=10.52}}
}
2 changes: 2 additions & 0 deletions test/Sema/availability_define.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func client() {
onMacOS10_15()
onMacOS11_0() // expected-error {{is only available in macOS 11.0 or newer}}
// expected-note @-1 {{add 'if #available' version check}}
// expected-note @-2 {{change the @available attribute of the global function on macOS from 10.15 to 11.0}}
onMacOSDeprecated()

if #available(_iOS14Aligned, *) {
Expand All @@ -68,6 +69,7 @@ func client() {
if #unavailable(_iOS14Aligned) {
onMacOS11_0() // expected-error {{is only available in macOS 11.0 or newer}}
// expected-note @-1 {{add 'if #available' version check}}
// expected-note @-2 {{change the @available attribute of the global function on macOS from 10.15 to 11.0}}
} else {
onMacOS11_0()
}
Expand Down
1 change: 1 addition & 0 deletions test/Sema/availability_swiftui.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ class AnyColorBox: LessAvailable {} // Ok, exception specifically for AnyColorBo
@available(macOS 10.15, *)
@usableFromInline
class OtherClass: LessAvailable {} // expected-error {{'LessAvailable' is only available in macOS 11 or newer; clients of 'SwiftUI' may have a lower deployment target}}
// expected-note @-1 {{change the @available attribute of the class on macOS from 10.15 to 11}} {{13:18-23=11}}
28 changes: 22 additions & 6 deletions test/Sema/availability_versions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func functionAvailableOn10_51() {

let _: Int = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the global function on macOS from 10.51 to 10.52}} {{43:29-34=10.52}}
}

// Still allow other availability annotations on script-mode globals
Expand Down Expand Up @@ -327,7 +328,8 @@ class ClassWithPotentiallyUnavailableProperties {
get {
let _: Int = availableOn10_51Stored // expected-error {{'availableOn10_51Stored' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

// expected-note@-2 {{change the @available attribute of the pattern binding on macOS from 10.9 to 10.51}} {{326:31-35=10.51}}

if #available(OSX 10.51, *) {
let _: Int = availableOn10_51Stored
}
Expand Down Expand Up @@ -409,10 +411,12 @@ class ClassWithReferencesInInitializers {
var propWithInitializer10_51: Int = globalFuncAvailableOn10_51()

var propWithInitializer10_52: Int = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
// expected-note@-1 {{change the @available attribute of the class on macOS from 10.51 to 10.52}} {{409:29-34=10.52}}

lazy var lazyPropWithInitializer10_51: Int = globalFuncAvailableOn10_51()

lazy var lazyPropWithInitializer10_52: Int = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
// expected-note@-1 {{change the @available attribute of the class on macOS from 10.51 to 10.52}} {{409:29-34=10.52}}
}

func accessPotentiallyUnavailableProperties(_ o: ClassWithPotentiallyUnavailableProperties) {
Expand Down Expand Up @@ -522,6 +526,7 @@ enum EnumIntroducedOn10_52 {

@available(OSX, introduced: 10.51)
enum CompassPoint {

case North
case South
case East
Expand All @@ -540,9 +545,11 @@ enum CompassPoint {
case WithAvailableByEnumElementPayload1(p : EnumIntroducedOn10_52), WithAvailableByEnumElementPayload2(p : EnumIntroducedOn10_52)

case WithPotentiallyUnavailablePayload(p : EnumIntroducedOn10_52) // expected-error {{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}
// expected-note@-1 {{change the @available attribute of the enum on macOS from 10.51 to 10.52}} {{527:29-34=10.52}}

case WithPotentiallyUnavailablePayload1(p : EnumIntroducedOn10_52), WithPotentiallyUnavailablePayload2(p : EnumIntroducedOn10_52) // expected-error 2{{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}

// expected-note@-1 2{{change the @available attribute of the enum on macOS from 10.51 to 10.52}} {{527:29-34=10.52}}

@available(OSX, unavailable)
case WithPotentiallyUnavailablePayload3(p : EnumIntroducedOn10_52)
}
Expand Down Expand Up @@ -878,18 +885,20 @@ class SubWithLargerMemberAvailability : SuperWithLimitedMemberAvailability {
override func someMethod() {
super.someMethod() // expected-error {{'someMethod()' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

// expected-note@-2 {{change the @available attribute of the instance method on macOS from 10.9 to 10.51}} {{884:31-35=10.51}}

if #available(OSX 10.51, *) {
super.someMethod()
}
}

@available(OSX, introduced: 10.9)
override var someProperty: Int {
get {
get {
let _ = super.someProperty // expected-error {{'someProperty' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the pattern binding on macOS from 10.9 to 10.51}} {{895:31-35=10.51}}

if #available(OSX 10.51, *) {
let _ = super.someProperty
}
Expand Down Expand Up @@ -961,6 +970,7 @@ protocol ProtocolAvailableOn10_51 {

@available(OSX, introduced: 10.9)
protocol ProtocolAvailableOn10_9InheritingFromProtocolAvailableOn10_51 : ProtocolAvailableOn10_51 { // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{change the @available attribute of the protocol on macOS from 10.9 to 10.51}} {{971:29-33=10.51}}
}

@available(OSX, introduced: 10.51)
Expand All @@ -973,6 +983,7 @@ protocol UnavailableProtocolInheritingFromProtocolAvailableOn10_51 : ProtocolAva

@available(OSX, introduced: 10.9)
class SubclassAvailableOn10_9OfClassAvailableOn10_51 : ClassAvailableOn10_51 { // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{change the @available attribute of the class on macOS from 10.9 to 10.51}} {{984:29-33=10.51}}
}

@available(OSX, unavailable)
Expand All @@ -997,12 +1008,14 @@ func castToPotentiallyUnavailableProtocol() {

@available(OSX, introduced: 10.9)
class SubclassAvailableOn10_9OfClassAvailableOn10_51AlsoAdoptingProtocolAvailableOn10_51 : ClassAvailableOn10_51, ProtocolAvailableOn10_51 { // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{change the @available attribute of the class on macOS from 10.9 to 10.51}} {{1009:29-33=10.51}}
}

class SomeGenericClass<T> { }

@available(OSX, introduced: 10.9)
class SubclassAvailableOn10_9OfSomeGenericClassOfProtocolAvailableOn10_51 : SomeGenericClass<ProtocolAvailableOn10_51> { // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{change the @available attribute of the class on macOS from 10.9 to 10.51}} {{1016:29-33=10.51}}
}

@available(OSX, unavailable)
Expand Down Expand Up @@ -1054,6 +1067,7 @@ extension ClassAvailableOn10_51 {
let _ = globalFuncAvailableOn10_51()
let _ = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the extension on macOS from 10.51 to 10.52}} {{1063:29-34=10.52}}
}
}

Expand Down Expand Up @@ -1655,6 +1669,7 @@ class ClassWithShortFormAvailableOn10_54 {
func funcWithShortFormAvailableOn10_9() {
let _ = ClassWithShortFormAvailableOn10_51() // expected-error {{'ClassWithShortFormAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the global function on macOS from 10.9 to 10.51}} {{1668:16-20=10.51}}
}

@available(OSX 10.51, *)
Expand Down Expand Up @@ -1689,6 +1704,7 @@ func funcWithMultipleShortFormAnnotationsForTheSamePlatform() {

let _ = ClassWithShortFormAvailableOn10_54() // expected-error {{'ClassWithShortFormAvailableOn10_54' is only available in macOS 10.54 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the global function on macOS from 10.52 to 10.54}} {{1701:16-21=10.54}}
}

func useShortFormAvailable() {
Expand Down
6 changes: 5 additions & 1 deletion test/Sema/availability_versions_multi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,21 @@ func useFromOtherOn99_51() {
o10_9.extensionMethodOnOtherIntroduced10_9AvailableOn99_51(o99_51)
_ = o99_51.returns99_52Introduced99_52() // expected-error {{'returns99_52Introduced99_52()' is only available in macOS 99.52 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the global function on macOS from 99.51 to 99.52}} {{26:29-34=99.52}}

_ = OtherIntroduced99_52()
// expected-error@-1 {{'OtherIntroduced99_52' is only available in macOS 99.52 or newer}}
// expected-note@-2 {{add 'if #available' version check}}
// expected-note@-3 {{change the @available attribute of the global function on macOS from 99.51 to 99.52}} {{26:29-34=99.52}}

o99_51.extensionMethodOnOtherIntroduced99_51AvailableOn99_52() // expected-error {{'extensionMethodOnOtherIntroduced99_51AvailableOn99_52()' is only available in macOS 99.52 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
// expected-note@-2 {{change the @available attribute of the global function on macOS from 99.51 to 99.52}} {{26:29-34=99.52}}

_ = OtherIntroduced99_51.NestedIntroduced99_52()
// expected-error@-1 {{'NestedIntroduced99_52' is only available in macOS 99.52 or newer}}
// expected-note@-2 {{add 'if #available' version check}}
// expected-note@-3 {{change the @available attribute of the global function on macOS from 99.51 to 99.52}} {{26:29-34=99.52}}
}

@available(OSX, introduced: 99.52)
Expand All @@ -55,7 +59,7 @@ func useFromOtherOn99_52() {
_ = n99_52.returns99_52()
_ = n99_52.returns99_53() // expected-error {{'returns99_53()' is only available in macOS 99.53 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

// expected-note@-2 {{change the @available attribute of the global function on macOS from 99.52 to 99.53}} {{54:29-34=99.53}}
// This will trigger validation of the global in availability_in_multi_other.swift
_ = globalFromOtherOn99_52
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// REQUIRES: OS=macosx

@main // expected-error {{'main()' is only available in macOS 10.99 or newer}}
// expected-note @-1 {{change the @available attribute of the struct on macOS from 10.0 to 10.99}}
@available(OSX 10.0, *)
struct EntryPoint {
@available(OSX 10.99, *)
Expand Down
1 change: 1 addition & 0 deletions test/attr/attr_availability_osx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func testMemberAvailability() {
TestStruct().doAnotherThing() // expected-error {{'doAnotherThing()' is unavailable}}
TestStruct().doThirdThing() // expected-error {{'doThirdThing()' is unavailable}}
TestStruct().doFourthThing() // expected-error {{'doFourthThing()' is only available in macOS 10.12 or newer}} expected-note {{'if #available'}}
// expected-note @-1 {{change the @available attribute of the global function on macOS from 10.11 to 10.12}}
TestStruct().doDeprecatedThing() // expected-warning {{'doDeprecatedThing()' is deprecated}}
}

Expand Down
Loading

0 comments on commit 765b2ec

Please sign in to comment.