Skip to content

Commit ce94c42

Browse files
dulmarodmeta-codesync[bot]
authored andcommitted
[test] SWIFT_NPE: pin out-of-scope shapes stay silent
Summary: Adds corpus fixtures pinning that three Swift shapes which look superficially like force-unwraps do NOT fire `SWIFT_NPE`, guarding against accidental over-reporting as the checker evolves: - `tryForceUnwrap_noSwiftNPE` — `try!` of a throwing call is an unhandled-error force-try, not a nil dereference. It lowers to `swift_unexpectedError` on the `error != nil` branch, a different shape from the Optional force-unwrap trap (`__sil_assert_fail` on `eq(disc, 0)`). The recogniser correctly leaves it alone, so it must stay out of `SWIFT_NPE` scope. - `optionalMap_good` / `optionalFlatMap_good` — `.map` / `.flatMap` propagate the Optional without force-unwrapping, so they can never trap. All three produce no report (the test baseline is unchanged), documenting the intended silence. Reviewed By: davidpichardie Differential Revision: D107524914 fbshipit-source-id: 4c545d5e2d74d84c69f079b707445aa179b67b41
1 parent 85fb0bd commit ce94c42

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

infer/tests/codetoanalyze/swift/interop-pulse/IUODerefTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,32 @@ func guardedUnwrap_good(_ x: Int?) -> Int {
244244
func interprocGuardedUnwrap_good() {
245245
_ = guardedUnwrap_good(nil)
246246
}
247+
248+
// MARK: - Out-of-scope shapes (must NOT fire SWIFT_NPE)
249+
250+
// `try!` of a throwing call is an unhandled-error force-try, not a nil
251+
// dereference: it lowers to `swift_unexpectedError` on the `error != nil`
252+
// branch, a different shape from the Optional force-unwrap trap. Pins that the
253+
// recogniser leaves it alone -- it must not be miscategorised as SWIFT_NPE.
254+
enum ForceTryError: Error { case boom }
255+
256+
@inline(never)
257+
func mayThrow(_ shouldThrow: Bool) throws -> Int {
258+
if shouldThrow { throw ForceTryError.boom }
259+
return 1
260+
}
261+
262+
func tryForceUnwrap_noSwiftNPE() -> Int {
263+
return try! mayThrow(true)
264+
}
265+
266+
// `.map` / `.flatMap` on an Optional propagate the Optional without
267+
// force-unwrapping; `??` substitutes a default. None can trap, so none should
268+
// fire SWIFT_NPE.
269+
func optionalMap_good(_ x: Int?) -> Int? {
270+
return x.map { $0 + 1 }
271+
}
272+
273+
func optionalFlatMap_good(_ x: Int?) -> Int? {
274+
return x.flatMap { Optional($0 + 1) }
275+
}

0 commit comments

Comments
 (0)