@@ -540,6 +540,22 @@ static bool parameterTypesMatch(const ValueDecl *derivedDecl,
540
540
return true ;
541
541
}
542
542
543
+ // / Returns true if the given declaration is for the `NSObject.hashValue`
544
+ // / property.
545
+ static bool isNSObjectHashValue (ValueDecl *baseDecl) {
546
+ ASTContext &ctx = baseDecl->getASTContext ();
547
+
548
+ if (auto baseVar = dyn_cast<VarDecl>(baseDecl)) {
549
+ if (auto classDecl = baseVar->getDeclContext ()->getSelfClassDecl ()) {
550
+ return baseVar->getName () == ctx.Id_hashValue &&
551
+ classDecl->getName ().is (" NSObject" ) &&
552
+ (classDecl->getModuleContext ()->getName () == ctx.Id_Foundation ||
553
+ classDecl->getModuleContext ()->getName () == ctx.Id_ObjectiveC );
554
+ }
555
+ }
556
+ return false ;
557
+ }
558
+
543
559
namespace {
544
560
// / Class that handles the checking of a particular declaration against
545
561
// / superclass entities that it could override.
@@ -786,9 +802,15 @@ static void checkOverrideAccessControl(ValueDecl *baseDecl, ValueDecl *decl,
786
802
baseDecl->getModuleContext () != decl->getModuleContext () &&
787
803
!isa<ConstructorDecl>(decl) &&
788
804
!isa<ProtocolDecl>(decl->getDeclContext ())) {
789
- diags.diagnose (decl, diag::override_of_non_open,
790
- decl->getDescriptiveKind ());
791
-
805
+ // NSObject.hashValue was made non-overridable in Swift 5; one should
806
+ // override NSObject.hash instead.
807
+ if (isNSObjectHashValue (baseDecl)) {
808
+ diags.diagnose (decl, diag::override_nsobject_hashvalue_error)
809
+ .fixItReplace (SourceRange (decl->getNameLoc ()), " hash" );
810
+ } else {
811
+ diags.diagnose (decl, diag::override_of_non_open,
812
+ decl->getDescriptiveKind ());
813
+ }
792
814
} else if (baseHasOpenAccess &&
793
815
classDecl->hasOpenAccess (dc) &&
794
816
decl->getFormalAccess () != AccessLevel::Open &&
@@ -1526,6 +1548,13 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
1526
1548
(isa<ExtensionDecl>(base->getDeclContext ()) ||
1527
1549
isa<ExtensionDecl>(override ->getDeclContext ())) &&
1528
1550
!base->isObjC ()) {
1551
+ // Suppress this diagnostic for overrides of a non-open NSObject.hashValue
1552
+ // property; these are diagnosed elsewhere. An error message complaining
1553
+ // about extensions would be misleading in this case; the correct fix is to
1554
+ // override NSObject.hash instead.
1555
+ if (isNSObjectHashValue (base) &&
1556
+ !base->hasOpenAccess (override ->getDeclContext ()))
1557
+ return true ;
1529
1558
bool baseCanBeObjC = canBeRepresentedInObjC (base);
1530
1559
diags.diagnose (override , diag::override_decl_extension, baseCanBeObjC,
1531
1560
!isa<ExtensionDecl>(base->getDeclContext ()));
@@ -1626,15 +1655,12 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
1626
1655
1627
1656
// Overrides of NSObject.hashValue are deprecated; one should override
1628
1657
// NSObject.hash instead.
1629
- if (auto baseVar = dyn_cast<VarDecl>(base)) {
1630
- if (auto classDecl = baseVar->getDeclContext ()->getSelfClassDecl ()) {
1631
- if (baseVar->getName () == ctx.Id_hashValue &&
1632
- classDecl->getName ().is (" NSObject" ) &&
1633
- (classDecl->getModuleContext ()->getName () == ctx.Id_Foundation ||
1634
- classDecl->getModuleContext ()->getName () == ctx.Id_ObjectiveC )) {
1635
- override ->diagnose (diag::override_nsobject_hashvalue);
1636
- }
1637
- }
1658
+ // FIXME: Remove this when NSObject.hashValue becomes non-open in
1659
+ // swift-corelibs-foundation.
1660
+ if (isNSObjectHashValue (base) &&
1661
+ base->hasOpenAccess (override ->getDeclContext ())) {
1662
+ override ->diagnose (diag::override_nsobject_hashvalue_warning)
1663
+ .fixItReplace (SourceRange (override ->getNameLoc ()), " hash" );
1638
1664
}
1639
1665
1640
1666
// / Check attributes associated with the base; some may need to merged with
0 commit comments