@@ -6,6 +6,10 @@ private import unified
66private import AllDataFlow
77
88private class SwiftDataFlowPlugin extends DataFlowPlugin {
9+ override predicate bypassContentSet ( ContentSet contents ) {
10+ contents .asSingleton ( ) .asNamedMember ( ) = "some.0"
11+ }
12+
913 // Note: For now we assume all code is Swift, but in the future we must restrict these rules to Swift-files
1014 override predicate step ( Node node1 , Step step , Node node2 ) {
1115 exists ( BinaryExpr expr |
@@ -27,33 +31,31 @@ private class SwiftDataFlowPlugin extends DataFlowPlugin {
2731 )
2832 or
2933 exists ( UnaryExpr expr |
30- expr .getOperator ( ) .( PostfixOperator ) .getValue ( ) = "!" and
31- node1 .isResultValue ( expr .getOperand ( ) ) and
32- ( step .readName ( "some.0" ) or step .taint ( ) ) and
33- node2 .isResultValue ( expr )
34+ expr .getOperator ( ) .( PostfixOperator ) .getValue ( ) = "!"
3435 or
35- expr .getOperator ( ) .( PrefixOperator ) .getValue ( ) = [ "try" , "try!" , "await" ] and
36+ expr .getOperator ( ) .( PrefixOperator ) .getValue ( ) = [ "try" , "try!" , "try?" , "await" ]
37+ |
3638 node1 .isResultValue ( expr .getOperand ( ) ) and
3739 step .value ( ) and
3840 node2 .isResultValue ( expr )
39- or
40- expr .getOperator ( ) .( PrefixOperator ) .getValue ( ) = "try?" and
41- // TODO: preserve the value of some.0 if it is already stored in that
42- node1 .isResultValue ( expr .getOperand ( ) ) and
43- step .storeName ( "some.0" ) and
44- node2 .isResultValue ( expr )
4541 )
4642 or
4743 exists ( TypeCastExpr expr |
48- // The `as?` type cast boxes the incoming value in Optional depending on whether the type cast succeeded
49- expr .getOperator ( ) .getValue ( ) = "as?" and
44+ // Type-cast operators:
45+ // - "as": Safe upcast conversion
46+ // - "as?": Wrap in Optional<T> if cast succeeds
47+ // - "as!": Throw if cast fails
48+ //
49+ // Since we bypass Optional<T> content, we model all of these as value steps.
50+ expr .getOperator ( ) .getValue ( ) = [ "as" , "as?" , "as!" ] and
5051 node1 .isResultValue ( expr .getExpr ( ) ) and
51- step .storeName ( "some.0" ) and
52+ step .value ( ) and
5253 node2 .isResultValue ( expr )
53- or
54- // Safe upcast conversion ("as") and downcast-or-throw ("as!") propagate the value directly
55- expr .getOperator ( ) .getValue ( ) = [ "as" , "as!" ] and
56- node1 .isResultValue ( expr .getExpr ( ) ) and
54+ )
55+ or
56+ exists ( NullCoalescingExpr expr |
57+ // We bypass Optional<T> content so we add value-flow out of both operands of "??"
58+ node1 .isResultValue ( expr .getAnOperand ( ) ) and
5759 step .value ( ) and
5860 node2 .isResultValue ( expr )
5961 )
0 commit comments