-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Swift: Query for escaping parameters of unsafe closures #13706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
rdmarsh2
wants to merge
9
commits into
main
Choose a base branch
from
rdmarsh2/swift/withUnsafeBytes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
1cac879
Initial test for pointer escaping withUnsafeBytes
rdmarsh2 83a787e
Swift: initial query for unsafe closure arg escape
rdmarsh2 f27522d
Swift: relocate UnsafePointerEscapesClosure
rdmarsh2 db18915
Swift: add more funcs to unsafe closure query
rdmarsh2 8120c8b
Swift: refactor to remove cartesian product
rdmarsh2 459eea5
Swift: avoid implicit return in tests
rdmarsh2 f125fa2
Swift: respond to PR comments
rdmarsh2 5f39a1a
Swift: qhelp for UnsafePointerEscapesClosure
rdmarsh2 37d69e5
Swift: add change note for unsafe closure query
rdmarsh2 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
111 changes: 9 additions & 102 deletions
111
swift/ql/test/query-tests/Security/CWE-825/UnsafePointerEscapesClosure.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,120 +1,27 @@ | ||
edges | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0] | | ||
| file://:0:0:0:0 | [post] self [field, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | | ||
| file://:0:0:0:0 | [post] self [field, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0] | | ||
| file://:0:0:0:0 | [post] self [field] | withUnsafeBytes.swift:33:9:33:9 | self[return] | | ||
| file://:0:0:0:0 | [post] self [field] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field] | | ||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [field] | | ||
| file://:0:0:0:0 | value [some:0, some:0, some:0, some:0] | file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | value [some:0, some:0, some:0] | file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | value [some:0, some:0] | file://:0:0:0:0 | [post] self [field, some:0, some:0] | | ||
| file://:0:0:0:0 | value [some:0] | file://:0:0:0:0 | [post] self [field, some:0] | | ||
| withUnsafeBytes.swift:9:25:9:25 | $0 | withUnsafeBytes.swift:10:16:10:16 | $0 | | ||
| withUnsafeBytes.swift:13:34:13:37 | p | withUnsafeBytes.swift:13:97:13:97 | p | | ||
| withUnsafeBytes.swift:15:34:15:37 | p | withUnsafeBytes.swift:15:109:15:109 | p | | ||
| withUnsafeBytes.swift:15:109:15:109 | p | withUnsafeBytes.swift:15:97:15:110 | call to id(pointer:) | | ||
| withUnsafeBytes.swift:15:109:15:109 | p | withUnsafeBytes.swift:28:12:28:21 | pointer | | ||
| withUnsafeBytes.swift:20:28:20:31 | p | withUnsafeBytes.swift:20:68:20:68 | p | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | withUnsafeBytes.swift:20:68:20:68 | p [some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | withUnsafeBytes.swift:33:9:33:9 | value | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0] | | ||
| withUnsafeBytes.swift:28:12:28:21 | pointer | withUnsafeBytes.swift:29:12:29:12 | pointer | | ||
| withUnsafeBytes.swift:28:12:28:21 | pointer | withUnsafeBytes.swift:29:12:29:12 | pointer | | ||
| withUnsafeBytes.swift:33:9:33:9 | value | file://:0:0:0:0 | value | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0, some:0] | file://:0:0:0:0 | value [some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0] | file://:0:0:0:0 | value [some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0] | file://:0:0:0:0 | value [some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0] | file://:0:0:0:0 | value [some:0] | | ||
| withUnsafeBytes.swift:15:109:15:109 | p | withUnsafeBytes.swift:38:12:38:21 | pointer | | ||
| withUnsafeBytes.swift:38:12:38:21 | pointer | withUnsafeBytes.swift:39:12:39:12 | pointer | | ||
| withUnsafeBytes.swift:38:12:38:21 | pointer | withUnsafeBytes.swift:39:12:39:12 | pointer | | ||
nodes | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0, some:0] | semmle.label | [post] self [field, some:0, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0, some:0] | semmle.label | [post] self [field, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | [post] self [field, some:0, some:0] | semmle.label | [post] self [field, some:0, some:0] | | ||
| file://:0:0:0:0 | [post] self [field, some:0] | semmle.label | [post] self [field, some:0] | | ||
| file://:0:0:0:0 | [post] self [field] | semmle.label | [post] self [field] | | ||
| file://:0:0:0:0 | value | semmle.label | value | | ||
| file://:0:0:0:0 | value [some:0, some:0, some:0, some:0] | semmle.label | value [some:0, some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | value [some:0, some:0, some:0] | semmle.label | value [some:0, some:0, some:0] | | ||
| file://:0:0:0:0 | value [some:0, some:0] | semmle.label | value [some:0, some:0] | | ||
| file://:0:0:0:0 | value [some:0] | semmle.label | value [some:0] | | ||
| withUnsafeBytes.swift:9:25:9:25 | $0 | semmle.label | $0 | | ||
| withUnsafeBytes.swift:10:16:10:16 | $0 | semmle.label | $0 | | ||
| withUnsafeBytes.swift:13:34:13:37 | p | semmle.label | p | | ||
| withUnsafeBytes.swift:13:97:13:97 | p | semmle.label | p | | ||
| withUnsafeBytes.swift:15:34:15:37 | p | semmle.label | p | | ||
| withUnsafeBytes.swift:15:97:15:110 | call to id(pointer:) | semmle.label | call to id(pointer:) | | ||
| withUnsafeBytes.swift:15:109:15:109 | p | semmle.label | p | | ||
| withUnsafeBytes.swift:20:28:20:31 | p | semmle.label | p | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... | semmle.label | ... = ... | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0, some:0] | semmle.label | ... = ... [field, some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0] | semmle.label | ... = ... [field, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0] | semmle.label | ... = ... [field, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0] | semmle.label | ... = ... [field, some:0] | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... [field] | semmle.label | ... = ... [field] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | semmle.label | p | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | semmle.label | p [some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | semmle.label | p [some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | semmle.label | p [some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | semmle.label | p [some:0] | | ||
| withUnsafeBytes.swift:28:12:28:21 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:28:12:28:21 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:29:12:29:12 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:29:12:29:12 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] | semmle.label | self[return] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] | semmle.label | self[return] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] | semmle.label | self[return] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] | semmle.label | self[return] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] | semmle.label | self[return] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0, some:0, some:0] | semmle.label | self[return] [field, some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0, some:0] | semmle.label | self[return] [field, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0] | semmle.label | self[return] [field, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0] | semmle.label | self[return] [field, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | self[return] [field] | semmle.label | self[return] [field] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value | semmle.label | value | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0, some:0] | semmle.label | value [some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0] | semmle.label | value [some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0] | semmle.label | value [some:0, some:0] | | ||
| withUnsafeBytes.swift:33:9:33:9 | value [some:0] | semmle.label | value [some:0] | | ||
| withUnsafeBytes.swift:38:12:38:21 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:38:12:38:21 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:39:12:39:12 | pointer | semmle.label | pointer | | ||
| withUnsafeBytes.swift:39:12:39:12 | pointer | semmle.label | pointer | | ||
subpaths | ||
| withUnsafeBytes.swift:15:109:15:109 | p | withUnsafeBytes.swift:28:12:28:21 | pointer | withUnsafeBytes.swift:29:12:29:12 | pointer | withUnsafeBytes.swift:15:97:15:110 | call to id(pointer:) | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | withUnsafeBytes.swift:33:9:33:9 | value | withUnsafeBytes.swift:33:9:33:9 | self[return] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p | withUnsafeBytes.swift:33:9:33:9 | value | withUnsafeBytes.swift:33:9:33:9 | self[return] [field] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0, some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0, some:0] | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] | withUnsafeBytes.swift:20:58:20:68 | ... = ... | | ||
| withUnsafeBytes.swift:20:68:20:68 | p [some:0] | withUnsafeBytes.swift:33:9:33:9 | value [some:0] | withUnsafeBytes.swift:33:9:33:9 | self[return] [field, some:0] | withUnsafeBytes.swift:20:58:20:68 | ... = ... [field, some:0] | | ||
| withUnsafeBytes.swift:15:109:15:109 | p | withUnsafeBytes.swift:38:12:38:21 | pointer | withUnsafeBytes.swift:39:12:39:12 | pointer | withUnsafeBytes.swift:15:97:15:110 | call to id(pointer:) | | ||
#select | ||
| withUnsafeBytes.swift:10:16:10:16 | $0 | withUnsafeBytes.swift:9:25:9:25 | $0 | withUnsafeBytes.swift:10:16:10:16 | $0 | This unsafe parameter may escape its invocation | | ||
| withUnsafeBytes.swift:13:97:13:97 | p | withUnsafeBytes.swift:13:34:13:37 | p | withUnsafeBytes.swift:13:97:13:97 | p | This unsafe parameter may escape its invocation | | ||
| withUnsafeBytes.swift:15:97:15:110 | call to id(pointer:) | withUnsafeBytes.swift:15:34:15:37 | p | withUnsafeBytes.swift:15:97:15:110 | call to id(pointer:) | This unsafe parameter may escape its invocation | | ||
| withUnsafeBytes.swift:20:58:20:68 | ... = ... | withUnsafeBytes.swift:20:28:20:31 | p | withUnsafeBytes.swift:20:58:20:68 | ... = ... | This unsafe parameter may escape its invocation | | ||
| withUnsafeBytes.swift:29:12:29:12 | pointer | withUnsafeBytes.swift:28:12:28:21 | pointer | withUnsafeBytes.swift:29:12:29:12 | pointer | This unsafe parameter may escape its invocation | | ||
| withUnsafeBytes.swift:39:12:39:12 | pointer | withUnsafeBytes.swift:38:12:38:21 | pointer | withUnsafeBytes.swift:39:12:39:12 | pointer | This unsafe parameter may escape its invocation | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,12 +17,22 @@ func arrayTest() { | |
ints.withUnsafeBytes({(p: UnsafeRawBufferPointer) in print(p)}) // GOOD | ||
|
||
var v = PointerHolder() | ||
ints.withUnsafeBytes({(p: UnsafeRawBufferPointer) in v.field = p}) // BAD | ||
ints.withUnsafeBytes({(p: UnsafeRawBufferPointer) in | ||
v.field = p | ||
return 1 | ||
}) // BAD | ||
print(v.field) | ||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
ints.withUnsafeBytes(myPrint) // GOOD | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another variant here would be calling a member function that stores the pointer argument in the object it's called on for later use. The effect is similar to the |
||
|
||
myPrint(p: ints.withUnsafeBytes(id)) // BAD | ||
|
||
var v2: UnsafeRawBufferPointer? = nil | ||
ints.withUnsafeBytes({(p: UnsafeRawBufferPointer) in | ||
v2 = p | ||
return 1 | ||
}) // BAD | ||
print(v2) | ||
} | ||
|
||
func id<T>(pointer: T) -> T { | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the issue with implicit returns? Surely we will see them in real world code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is that we were picking up the implicit return of the assignment, but not the field being assigned. This is currently not detected... I think there's some missing flow for closure captures.