Skip to content

Commit 3439333

Browse files
authored
Merge pull request #18407 from DougGregor/warn-override-nsobject-hashvalue
[Type checker] Warn about overrides of NSObject.hashValue.
2 parents 8144728 + cc4c992 commit 3439333

File tree

5 files changed

+32
-12
lines changed

5 files changed

+32
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4142,6 +4142,10 @@ NOTE(redundant_particular_literal_case_here,none,
41424142

41434143
WARNING(non_exhaustive_switch_warn,none, "switch must be exhaustive", ())
41444144

4145+
WARNING(override_nsobject_hashvalue,none,
4146+
"override of 'NSObject.hashValue' is deprecated; "
4147+
"override 'NSObject.hash' to get consistent hashing behavior", ())
4148+
41454149
#ifndef DIAG_NO_UNDEF
41464150
# if defined(DIAG)
41474151
# undef DIAG

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,18 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
15191519
diagnoseOverrideForAvailability(override, base);
15201520
}
15211521

1522+
// Overrides of NSObject.hashValue are deprecated; one should override
1523+
// NSObject.hash instead.
1524+
if (auto baseVar = dyn_cast<VarDecl>(base)) {
1525+
if (auto classDecl =
1526+
baseVar->getDeclContext()->getAsClassOrClassExtensionContext()) {
1527+
if (classDecl->getBaseName().userFacingName() == "NSObject" &&
1528+
baseVar->getBaseName().userFacingName() == "hashValue") {
1529+
override->diagnose(diag::override_nsobject_hashvalue);
1530+
}
1531+
}
1532+
}
1533+
15221534
/// Check attributes associated with the base; some may need to merged with
15231535
/// or checked against attributes in the overriding declaration.
15241536
AttributeOverrideChecker attrChecker(base, override);

test/ClangImporter/objc_override.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ class CallbackSubC : CallbackBase {
108108
override func perform(optNonescapingHandler: @escaping () -> Void) {} // expected-error {{method does not override any method from its superclass}}
109109
}
110110

111+
//
112+
class MyHashableNSObject: NSObject {
113+
override var hashValue: Int { // expected-warning{{override of 'NSObject.hashValue' is deprecated}}
114+
return 0
115+
}
116+
}
117+
118+
111119
// FIXME: Remove -verify-ignore-unknown.
112120
// <unknown>:0: error: unexpected note produced: overridden declaration is here
113121
// <unknown>:0: error: unexpected note produced: setter for 'boolProperty' declared here

test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22
@_exported import CoreGraphics
33
@_exported import Foundation
44

5-
public func == (lhs: NSObject, rhs: NSObject) -> Bool {
6-
return lhs.isEqual(rhs)
5+
extension NSObject : Equatable, Hashable {
6+
@objc open var hashValue: Int {
7+
return hash
8+
}
9+
10+
public static func == (lhs: NSObject, rhs: NSObject) -> Bool {
11+
return lhs.isEqual(rhs)
12+
}
713
}
814

915
public let NSUTF8StringEncoding: UInt = 8

test/Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,3 @@ public func _convertObjCBoolToBool(_ x: ObjCBool) -> Bool {
8686
public func ~=(x: NSObject, y: NSObject) -> Bool {
8787
return true
8888
}
89-
90-
extension NSObject : Equatable, Hashable {
91-
public var hashValue: Int {
92-
return hash
93-
}
94-
}
95-
96-
public func == (lhs: NSObject, rhs: NSObject) -> Bool {
97-
return lhs.isEqual(rhs)
98-
}

0 commit comments

Comments
 (0)