Skip to content

Commit 35e1789

Browse files
LaurenWhiteallevato
authored andcommitted
Implement never force unwrap (swiftlang#77)
1 parent 0f2719b commit 35e1789

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

Diff for: Sources/Rules/NeverForceUnwrap.swift

+24
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,29 @@ import SwiftSyntax
88
///
99
/// - SeeAlso: https://google.github.io/swift#force-unwrapping-and-force-casts
1010
public final class NeverForceUnwrap: SyntaxLintRule {
11+
12+
// Checks if "XCTest" is an import statement
13+
public override func visit(_ node: SourceFileSyntax) {
14+
setImportsXCTest(context: context, sourceFile: node)
15+
super.visit(node)
16+
}
17+
18+
public override func visit(_ node: ForcedValueExprSyntax) {
19+
guard !context.importsXCTest else { return }
20+
diagnose(.doNotForceUnwrap(name: node.expression.description), on: node)
21+
}
22+
23+
public override func visit(_ node: AsExprSyntax) {
24+
guard !context.importsXCTest else { return }
25+
diagnose(.doNotForceCast(name: node.typeName.description), on: node)
26+
}
27+
}
1128

29+
extension Diagnostic.Message {
30+
static func doNotForceUnwrap(name: String) -> Diagnostic.Message {
31+
return .init(.warning, "do not force unwrap '\(name)'")
32+
}
33+
static func doNotForceCast(name: String) -> Diagnostic.Message {
34+
return .init(.warning, "do not force cast to '\(name)'")
35+
}
1236
}

Diff for: Tests/SwiftFormatTests/NeverForceUnwrapTests.swift

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Foundation
2+
import SwiftSyntax
3+
import XCTest
4+
5+
@testable import Rules
6+
7+
public class NeverForceUnwrapTests: DiagnosingTestCase {
8+
public func testUnsafeUnwrap() {
9+
let input =
10+
"""
11+
func someFunc() -> Int {
12+
var a = getInt()
13+
var b = a as! Int
14+
let c = (someValue())!
15+
let d = String(a)!
16+
let regex = try! NSRegularExpression(pattern: "a*b+c?")
17+
return a!
18+
}
19+
"""
20+
performLint(NeverForceUnwrap.self, input: input)
21+
XCTAssertDiagnosed(.doNotForceCast(name: "Int"))
22+
XCTAssertDiagnosed(.doNotForceUnwrap(name: "(someValue())"))
23+
XCTAssertDiagnosed(.doNotForceUnwrap(name: "String(a)"))
24+
XCTAssertNotDiagnosed(.doNotForceCast(name: "try"))
25+
XCTAssertNotDiagnosed(.doNotForceUnwrap(name: "try"))
26+
XCTAssertDiagnosed(.doNotForceUnwrap(name: "a"))
27+
}
28+
public func testIgnoreTestCode() {
29+
let input =
30+
"""
31+
import XCTest
32+
33+
var b = a as! Int
34+
"""
35+
performLint(NeverUseImplicitlyUnwrappedOptionals.self, input: input)
36+
XCTAssertNotDiagnosed(.doNotForceCast(name: "Int"))
37+
}
38+
39+
#if !os(macOS)
40+
static let allTests = [
41+
NeverForceUnwrapTests.testUnsafeUnwrap,
42+
]
43+
#endif
44+
}
45+
46+

0 commit comments

Comments
 (0)