Skip to content

Commit e67fe08

Browse files
committed
Improve message when trying to override an unavailable member.
1 parent 2fd0b39 commit e67fe08

File tree

6 files changed

+72
-5
lines changed

6 files changed

+72
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,8 +1371,12 @@ NOTE(overridden_here_with_type,none,
13711371
"overridden declaration here has type %0", (Type))
13721372
ERROR(missing_override,none,
13731373
"overriding declaration requires an 'override' keyword", ())
1374+
13741375
ERROR(override_unavailable,none,
13751376
"cannot override %0 which has been marked unavailable", (Identifier))
1377+
ERROR(override_unavailable_msg, none,
1378+
"cannot override %0 which has been marked unavailable: %1",
1379+
(Identifier, StringRef))
13761380

13771381
ERROR(override_less_available,none,
13781382
"overriding %0 must be as available as declaration it overrides",

lib/Sema/MiscDiagnostics.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,18 @@ bool TypeChecker::diagnoseExplicitUnavailability(const ValueDecl *D,
13521352
SourceRange R,
13531353
const DeclContext *DC,
13541354
const CallExpr *CE) {
1355+
return diagnoseExplicitUnavailability(D, R, DC,
1356+
[=](InFlightDiagnostic &diag) {
1357+
fixItAvailableAttrRename(*this, diag, R, AvailableAttr::isUnavailable(D),
1358+
CE);
1359+
});
1360+
}
1361+
1362+
bool TypeChecker::diagnoseExplicitUnavailability(
1363+
const ValueDecl *D,
1364+
SourceRange R,
1365+
const DeclContext *DC,
1366+
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts) {
13551367
auto *Attr = AvailableAttr::isUnavailable(D);
13561368
if (!Attr)
13571369
return false;
@@ -1388,12 +1400,12 @@ bool TypeChecker::diagnoseExplicitUnavailability(const ValueDecl *D,
13881400
auto diag = diagnose(Loc, diag::availability_decl_unavailable_rename,
13891401
Name, replaceKind.hasValue(), rawReplaceKind,
13901402
newName);
1391-
fixItAvailableAttrRename(*this, diag, R, Attr, CE);
1403+
attachRenameFixIts(diag);
13921404
} else {
13931405
auto diag = diagnose(Loc,diag::availability_decl_unavailable_rename_msg,
13941406
Name, replaceKind.hasValue(), rawReplaceKind,
13951407
newName, Attr->Message);
1396-
fixItAvailableAttrRename(*this, diag, R, Attr, CE);
1408+
attachRenameFixIts(diag);
13971409
}
13981410
} else if (Attr->Message.empty()) {
13991411
diagnose(Loc, diag::availability_decl_unavailable, Name).highlight(R);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5478,6 +5478,28 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
54785478
return true;
54795479
}
54805480

5481+
static void diagnoseUnavailableOverride(TypeChecker &TC,
5482+
const ValueDecl *override,
5483+
const ValueDecl *base,
5484+
const AvailableAttr *attr) {
5485+
if (attr->Rename.empty()) {
5486+
if (attr->Message.empty())
5487+
TC.diagnose(override, diag::override_unavailable, override->getName());
5488+
else
5489+
TC.diagnose(override, diag::override_unavailable_msg,
5490+
override->getName(), attr->Message);
5491+
TC.diagnose(base, diag::availability_marked_unavailable,
5492+
base->getFullName());
5493+
return;
5494+
}
5495+
5496+
TC.diagnoseExplicitUnavailability(base, override->getLoc(),
5497+
override->getDeclContext(),
5498+
[](InFlightDiagnostic &diag) {
5499+
// FIXME: Apply fix-its here.
5500+
});
5501+
}
5502+
54815503
/// Record that the \c overriding declarations overrides the
54825504
/// \c overridden declaration.
54835505
///
@@ -5580,8 +5602,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
55805602
}
55815603

55825604
// FIXME: Possibly should extend to more availability checking.
5583-
if (base->getAttrs().isUnavailable(TC.Context)) {
5584-
TC.diagnose(override, diag::override_unavailable, override->getName());
5605+
if (auto *attr = base->getAttrs().getUnavailable(TC.Context)) {
5606+
diagnoseUnavailableOverride(TC, override, base, attr);
55855607
}
55865608

55875609
if (!TC.getLangOpts().DisableAvailabilityChecking) {

lib/Sema/TypeChecker.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,6 +1576,14 @@ class TypeChecker final : public LazyResolver {
15761576
const DeclContext *DC,
15771577
const CallExpr *CE);
15781578

1579+
/// Emit a diagnostic for references to declarations that have been
1580+
/// marked as unavailable, either through "unavailable" or "obsoleted:".
1581+
bool diagnoseExplicitUnavailability(
1582+
const ValueDecl *D,
1583+
SourceRange R,
1584+
const DeclContext *DC,
1585+
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts);
1586+
15791587
/// @}
15801588

15811589
/// \name Overload resolution

test/Sema/availability.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func foo(x : NSUInteger) { // expected-error {{'NSUInteger' is unavailable: use
1919
// Test preventing overrides of unavailable methods.
2020
class ClassWithUnavailable {
2121
@available(*, unavailable)
22-
func doNotOverride() {}
22+
func doNotOverride() {} // expected-note {{'doNotOverride()' has been explicitly marked unavailable here}}
2323

2424
// FIXME: extraneous diagnostic here
2525
@available(*, unavailable)

test/attr/attr_availability.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,24 @@ func testFactoryMethods() {
496496
Int.factory(other: 1) // expected-error {{'factory(other:)' has been replaced by 'init(other:)'}} {{6-14=}}
497497
Int.factory2(other: 1) // expected-error {{'factory2(other:)' has been replaced by 'Int.init(other:)'}} {{3-15=Int}}
498498
}
499+
500+
class Base {
501+
@available(*, unavailable)
502+
func bad() {} // expected-note {{here}}
503+
504+
@available(*, unavailable, message: "it was smelly")
505+
func smelly() {} // expected-note {{here}}
506+
507+
@available(*, unavailable, renamed: "new")
508+
func old() {} // expected-note {{here}}
509+
510+
@available(*, unavailable, renamed: "new", message: "it was smelly")
511+
func oldAndSmelly() {} // expected-note {{here}}
512+
}
513+
514+
class Sub : Base {
515+
override func bad() {} // expected-error {{cannot override 'bad' which has been marked unavailable}} {{none}}
516+
override func smelly() {} // expected-error {{cannot override 'smelly' which has been marked unavailable: it was smelly}} {{none}}
517+
override func old() {} // expected-error {{'old()' has been renamed to 'new'}} {{none}}
518+
override func oldAndSmelly() {} // expected-error {{'oldAndSmelly()' has been renamed to 'new': it was smelly}} {{none}}
519+
}

0 commit comments

Comments
 (0)