Skip to content

Commit 6f56a65

Browse files
authored
Merge pull request #14761 from geoffw0/moderntest
Swift: Update the inline dataflow tests
2 parents d931ade + c3577b3 commit 6f56a65

File tree

15 files changed

+142
-181
lines changed

15 files changed

+142
-181
lines changed

swift/ql/test/TestUtilities/InlineFlowTest.qll

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
1717
* Example of the corresponding test file, e.g. Test.java
1818
* ```swift
19-
* func source() -> Any { return nil }
20-
* func taint() -> Any { return nil }
19+
* func source(_ label: String) -> Any { return nil }
20+
* func taint(_ label: String) -> Any { return nil }
2121
* func sink(_ o: Any) { }
2222
*
2323
* func test() {
24-
* let s = source()
25-
* sink(s) // $ hasValueFlow
26-
* let t = "foo" + taint()
27-
* sink(t); // $ hasTaintFlow
24+
* let s = source("mySource")
25+
* sink(s) // $ hasValueFlow=mySource
26+
* let t = "foo" + taint("myTaint")
27+
* sink(t); // $ hasTaintFlow=myTaint
2828
* }
2929
* ```
3030
*
@@ -42,11 +42,17 @@ import codeql.swift.dataflow.TaintTracking
4242
import TestUtilities.InlineExpectationsTest
4343

4444
private predicate defaultSource(DataFlow::Node source) {
45-
source.asExpr().(CallExpr).getStaticTarget().(Function).getShortName() = ["source", "taint"]
45+
source
46+
.asExpr()
47+
.(CallExpr)
48+
.getStaticTarget()
49+
.(Function)
50+
.getShortName()
51+
.matches(["source%", "taint"])
4652
}
4753

4854
private predicate defaultSink(DataFlow::Node sink) {
49-
exists(CallExpr ca | ca.getStaticTarget().(Function).getShortName() = "sink" |
55+
exists(CallExpr ca | ca.getStaticTarget().(Function).getShortName().matches("sink%") |
5056
sink.asExpr() = ca.getAnArgument().getExpr()
5157
)
5258
}
@@ -59,40 +65,55 @@ module DefaultFlowConfig implements DataFlow::ConfigSig {
5965
int fieldFlowBranchLimit() { result = 1000 }
6066
}
6167

62-
private module NoFlowConfig implements DataFlow::ConfigSig {
68+
module NoFlowConfig implements DataFlow::ConfigSig {
6369
predicate isSource(DataFlow::Node source) { none() }
6470

6571
predicate isSink(DataFlow::Node sink) { none() }
6672
}
6773

74+
private signature string valueFlowTagSig();
75+
76+
private signature string taintFlowTagSig();
77+
78+
string defaultValueFlowTag() { result = "hasValueFlow" }
79+
80+
string defaultTaintFlowTag() { result = "hasTaintFlow" }
81+
6882
private string getSourceArgString(DataFlow::Node src) {
6983
defaultSource(src) and
7084
src.asExpr().(CallExpr).getAnArgument().getExpr().(StringLiteralExpr).getValue() = result
7185
}
7286

73-
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
87+
module FlowTest<
88+
DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig,
89+
valueFlowTagSig/0 valueFlowTag, taintFlowTagSig/0 taintFlowTag>
90+
{
7491
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
7592

7693
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
7794

7895
private module InlineTest implements TestSig {
79-
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
96+
string getARelevantTag() { result = [valueFlowTag(), taintFlowTag()] }
8097

8198
predicate hasActualResult(Location location, string element, string tag, string value) {
82-
tag = "hasValueFlow" and
99+
tag = valueFlowTag() and
83100
exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) |
84101
sink.getLocation() = location and
85102
element = sink.toString() and
86-
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
103+
if exists(getSourceArgString(src))
104+
then value = getSourceArgString(src)
105+
else value = src.getLocation().getStartLine().toString()
87106
)
88107
or
89-
tag = "hasTaintFlow" and
108+
tag = taintFlowTag() and
90109
exists(DataFlow::Node src, DataFlow::Node sink |
91110
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
92111
|
93112
sink.getLocation() = location and
94113
element = sink.toString() and
95-
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
114+
if exists(getSourceArgString(src))
115+
then value = getSourceArgString(src)
116+
else value = src.getLocation().getStartLine().toString()
96117
)
97118
}
98119
}
@@ -106,12 +127,13 @@ module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFl
106127
}
107128
}
108129

109-
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
130+
module DefaultFlowTest =
131+
FlowTest<DefaultFlowConfig, DefaultFlowConfig, defaultValueFlowTag/0, defaultTaintFlowTag/0>;
110132

111133
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
112-
import FlowTest<ValueFlowConfig, NoFlowConfig>
134+
import FlowTest<ValueFlowConfig, NoFlowConfig, defaultValueFlowTag/0, defaultTaintFlowTag/0>
113135
}
114136

115137
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
116-
import FlowTest<NoFlowConfig, TaintFlowConfig>
138+
import FlowTest<NoFlowConfig, TaintFlowConfig, defaultValueFlowTag/0, defaultTaintFlowTag/0>
117139
}

swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -604,8 +604,8 @@ edges
604604
| test.swift:884:15:884:15 | generator [Collection element] | test.swift:884:15:884:30 | call to next() [some:0] |
605605
| test.swift:884:15:884:30 | call to next() [some:0] | test.swift:884:15:884:31 | ...! |
606606
| test.swift:908:19:908:26 | call to source() | test.swift:904:13:904:18 | call to ... |
607-
| test.swift:927:12:927:21 | call to source() | test.swift:927:12:927:21 | OpenExistentialExpr |
608-
| test.swift:929:12:929:35 | call to source() | test.swift:929:12:929:35 | OpenExistentialExpr |
607+
| test.swift:927:12:927:31 | call to source(_:) | test.swift:927:12:927:31 | OpenExistentialExpr |
608+
| test.swift:929:12:929:57 | call to source(_:) | test.swift:929:12:929:57 | OpenExistentialExpr |
609609
nodes
610610
| file://:0:0:0:0 | .a [x] | semmle.label | .a [x] |
611611
| file://:0:0:0:0 | .s [x] | semmle.label | .s [x] |
@@ -1256,12 +1256,12 @@ nodes
12561256
| test.swift:884:15:884:31 | ...! | semmle.label | ...! |
12571257
| test.swift:904:13:904:18 | call to ... | semmle.label | call to ... |
12581258
| test.swift:908:19:908:26 | call to source() | semmle.label | call to source() |
1259-
| test.swift:927:12:927:21 | OpenExistentialExpr | semmle.label | OpenExistentialExpr |
1260-
| test.swift:927:12:927:21 | call to source() | semmle.label | call to source() |
1261-
| test.swift:928:12:928:21 | call to source() | semmle.label | call to source() |
1262-
| test.swift:929:12:929:35 | OpenExistentialExpr | semmle.label | OpenExistentialExpr |
1263-
| test.swift:929:12:929:35 | call to source() | semmle.label | call to source() |
1264-
| test.swift:930:12:930:39 | call to source() | semmle.label | call to source() |
1259+
| test.swift:927:12:927:31 | OpenExistentialExpr | semmle.label | OpenExistentialExpr |
1260+
| test.swift:927:12:927:31 | call to source(_:) | semmle.label | call to source(_:) |
1261+
| test.swift:928:12:928:31 | call to source(_:) | semmle.label | call to source(_:) |
1262+
| test.swift:929:12:929:57 | OpenExistentialExpr | semmle.label | OpenExistentialExpr |
1263+
| test.swift:929:12:929:57 | call to source(_:) | semmle.label | call to source(_:) |
1264+
| test.swift:930:12:930:65 | call to source(_:) | semmle.label | call to source(_:) |
12651265
subpaths
12661266
| test.swift:75:22:75:22 | x | test.swift:65:16:65:28 | arg1 | test.swift:65:1:70:1 | arg2[return] | test.swift:75:32:75:32 | [post] y |
12671267
| test.swift:114:19:114:19 | arg | test.swift:109:9:109:14 | arg | test.swift:110:12:110:12 | arg | test.swift:114:12:114:22 | call to ... |
@@ -1460,7 +1460,7 @@ subpaths
14601460
| test.swift:880:19:880:19 | elem | test.swift:877:21:877:28 | call to source() | test.swift:880:19:880:19 | elem | result |
14611461
| test.swift:884:15:884:31 | ...! | test.swift:877:21:877:28 | call to source() | test.swift:884:15:884:31 | ...! | result |
14621462
| test.swift:904:13:904:18 | call to ... | test.swift:908:19:908:26 | call to source() | test.swift:904:13:904:18 | call to ... | result |
1463-
| test.swift:927:12:927:21 | OpenExistentialExpr | test.swift:927:12:927:21 | call to source() | test.swift:927:12:927:21 | OpenExistentialExpr | result |
1464-
| test.swift:928:12:928:21 | call to source() | test.swift:928:12:928:21 | call to source() | test.swift:928:12:928:21 | call to source() | result |
1465-
| test.swift:929:12:929:35 | OpenExistentialExpr | test.swift:929:12:929:35 | call to source() | test.swift:929:12:929:35 | OpenExistentialExpr | result |
1466-
| test.swift:930:12:930:39 | call to source() | test.swift:930:12:930:39 | call to source() | test.swift:930:12:930:39 | call to source() | result |
1463+
| test.swift:927:12:927:31 | OpenExistentialExpr | test.swift:927:12:927:31 | call to source(_:) | test.swift:927:12:927:31 | OpenExistentialExpr | result |
1464+
| test.swift:928:12:928:31 | call to source(_:) | test.swift:928:12:928:31 | call to source(_:) | test.swift:928:12:928:31 | call to source(_:) | result |
1465+
| test.swift:929:12:929:57 | OpenExistentialExpr | test.swift:929:12:929:57 | call to source(_:) | test.swift:929:12:929:57 | OpenExistentialExpr | result |
1466+
| test.swift:930:12:930:65 | call to source(_:) | test.swift:930:12:930:65 | call to source(_:) | test.swift:930:12:930:65 | call to source(_:) | result |
Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
1-
import swift
1+
import TestUtilities.InlineFlowTest
22
import FlowConfig
3-
import TestUtilities.InlineExpectationsTest
43

5-
module TaintTest implements TestSig {
6-
string getARelevantTag() { result = "flow" }
4+
string customTaintFlowTag() { result = "flow" }
75

8-
predicate hasActualResult(Location location, string element, string tag, string value) {
9-
exists(DataFlow::Node source, DataFlow::Node sink, Expr sinkExpr |
10-
TestFlow::flow(source, sink) and
11-
sinkExpr = sink.asExpr() and
12-
location = sinkExpr.getLocation() and
13-
element = sinkExpr.toString() and
14-
tag = "flow" and
15-
value = source.asExpr().getLocation().getStartLine().toString()
16-
)
17-
}
18-
}
19-
20-
import MakeTest<TaintTest>
6+
import FlowTest<DefaultFlowConfig, NoFlowConfig, customTaintFlowTag/0, defaultTaintFlowTag/0>

swift/ql/test/library-tests/dataflow/dataflow/FlowConfig.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import codeql.swift.frameworks.Frameworks
99

1010
module TestConfiguration implements DataFlow::ConfigSig {
1111
predicate isSource(DataFlow::Node src) {
12-
src.asExpr().(CallExpr).getStaticTarget().getName().matches("source%()")
12+
src.asExpr().(CallExpr).getStaticTarget().getName().matches("source%")
1313
}
1414

1515
predicate isSink(DataFlow::Node sink) {

swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,11 +1159,11 @@
11591159
| test.swift:917:7:917:7 | SSA def(self) | test.swift:917:7:917:7 | self[return] |
11601160
| test.swift:917:7:917:7 | self | test.swift:917:7:917:7 | SSA def(self) |
11611161
| test.swift:917:7:917:7 | self | test.swift:917:7:917:7 | SSA def(self) |
1162-
| test.swift:918:7:918:7 | SSA def(self) | test.swift:918:2:918:34 | self[return] |
1162+
| test.swift:918:7:918:7 | SSA def(self) | test.swift:918:2:918:49 | self[return] |
11631163
| test.swift:918:7:918:7 | self | test.swift:918:7:918:7 | SSA def(self) |
11641164
| test.swift:926:30:926:33 | SSA def(x) | test.swift:927:12:927:12 | x |
11651165
| test.swift:926:30:926:33 | x | test.swift:926:30:926:33 | SSA def(x) |
11661166
| test.swift:926:45:926:48 | SSA def(y) | test.swift:928:12:928:12 | y |
11671167
| test.swift:926:45:926:48 | y | test.swift:926:45:926:48 | SSA def(y) |
1168-
| test.swift:927:12:927:21 | call to source() | test.swift:927:12:927:21 | OpenExistentialExpr |
1169-
| test.swift:929:12:929:35 | call to source() | test.swift:929:12:929:35 | OpenExistentialExpr |
1168+
| test.swift:927:12:927:31 | call to source(_:) | test.swift:927:12:927:31 | OpenExistentialExpr |
1169+
| test.swift:929:12:929:57 | call to source(_:) | test.swift:929:12:929:57 | OpenExistentialExpr |

swift/ql/test/library-tests/dataflow/dataflow/test.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,11 +911,11 @@ func autoclosureTest() {
911911
// ---
912912

913913
protocol MyProtocol {
914-
func source() -> Int
914+
func source(_ label: String) -> Int
915915
}
916916

917917
class MyProcotolImpl : MyProtocol {
918-
func source() -> Int { return 0 }
918+
func source(_ label: String) -> Int { return 0 }
919919
}
920920

921921
func getMyProtocol() -> MyProtocol { return MyProcotolImpl() }
@@ -924,10 +924,10 @@ func getMyProtocolImpl() -> MyProcotolImpl { return MyProcotolImpl() }
924924
func sink(arg: Int) { }
925925

926926
func testOpenExistentialExpr(x: MyProtocol, y: MyProcotolImpl) {
927-
sink(arg: x.source()) // $ flow=927
928-
sink(arg: y.source()) // $ flow=928
929-
sink(arg: getMyProtocol().source()) // $ flow=929
930-
sink(arg: getMyProtocolImpl().source()) // $ flow=930
927+
sink(arg: x.source("x.source")) // $ flow=x.source
928+
sink(arg: y.source("y.source")) // $ flow=y.source
929+
sink(arg: getMyProtocol().source("getMyProtocol.source")) // $ flow=getMyProtocol.source
930+
sink(arg: getMyProtocolImpl().source("getMyProtocolImpl.source")) // $ flow=getMyProtocolImpl.source
931931
}
932932

933933
// ---

swift/ql/test/library-tests/dataflow/taint/core/LocalTaint.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@
187187
| conversions.swift:170:2:170:2 | self | conversions.swift:170:2:170:2 | SSA def(self) |
188188
| conversions.swift:171:7:171:7 | SSA def(arr1) | conversions.swift:173:13:173:13 | arr1 |
189189
| conversions.swift:171:7:171:7 | arr1 | conversions.swift:171:7:171:7 | SSA def(arr1) |
190-
| conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:171:7:171:7 | arr1 |
190+
| conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:171:7:171:7 | arr1 |
191191
| conversions.swift:172:7:172:7 | SSA def(arr2) | conversions.swift:174:13:174:13 | arr2 |
192192
| conversions.swift:172:7:172:7 | arr2 | conversions.swift:172:7:172:7 | SSA def(arr2) |
193193
| conversions.swift:172:14:172:26 | [...] | conversions.swift:172:7:172:7 | arr2 |

swift/ql/test/library-tests/dataflow/taint/core/Taint.expected

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ edges
100100
| conversions.swift:156:25:156:69 | call to unsafeDowncast(_:to:) | conversions.swift:158:12:158:12 | v3 |
101101
| conversions.swift:156:40:156:40 | parent | conversions.swift:156:25:156:69 | call to unsafeDowncast(_:to:) |
102102
| conversions.swift:166:24:166:34 | call to sourceInt() | conversions.swift:166:12:166:35 | call to Self.init(_:) |
103-
| conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:173:13:173:13 | arr1 |
104-
| conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:175:13:175:19 | ...[...] |
105-
| conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:178:25:178:25 | arr1 |
106-
| conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:185:31:185:31 | arr1 |
103+
| conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:173:13:173:13 | arr1 |
104+
| conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:175:13:175:19 | ...[...] |
105+
| conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:178:25:178:25 | arr1 |
106+
| conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:185:31:185:31 | arr1 |
107107
| conversions.swift:172:14:172:26 | [...] [Collection element] | conversions.swift:174:13:174:13 | arr2 |
108108
| conversions.swift:172:14:172:26 | [...] [Collection element] | conversions.swift:176:13:176:13 | arr2 [Collection element] |
109109
| conversions.swift:172:14:172:26 | [...] [Collection element] | conversions.swift:176:13:176:19 | ...[...] |
@@ -357,7 +357,7 @@ nodes
357357
| conversions.swift:158:12:158:12 | v3 | semmle.label | v3 |
358358
| conversions.swift:166:12:166:35 | call to Self.init(_:) | semmle.label | call to Self.init(_:) |
359359
| conversions.swift:166:24:166:34 | call to sourceInt() | semmle.label | call to sourceInt() |
360-
| conversions.swift:171:14:171:26 | call to sourceArray() | semmle.label | call to sourceArray() |
360+
| conversions.swift:171:14:171:33 | call to sourceArray(_:) | semmle.label | call to sourceArray(_:) |
361361
| conversions.swift:172:14:172:26 | [...] [Collection element] | semmle.label | [...] [Collection element] |
362362
| conversions.swift:172:15:172:25 | call to sourceInt() | semmle.label | call to sourceInt() |
363363
| conversions.swift:173:13:173:13 | arr1 | semmle.label | arr1 |
@@ -573,17 +573,17 @@ subpaths
573573
| conversions.swift:157:12:157:12 | v3 | conversions.swift:152:31:152:44 | call to sourceString() | conversions.swift:157:12:157:12 | v3 | result |
574574
| conversions.swift:158:12:158:12 | v3 | conversions.swift:152:31:152:44 | call to sourceString() | conversions.swift:158:12:158:12 | v3 | result |
575575
| conversions.swift:166:12:166:35 | call to Self.init(_:) | conversions.swift:166:24:166:34 | call to sourceInt() | conversions.swift:166:12:166:35 | call to Self.init(_:) | result |
576-
| conversions.swift:173:13:173:13 | arr1 | conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:173:13:173:13 | arr1 | result |
576+
| conversions.swift:173:13:173:13 | arr1 | conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:173:13:173:13 | arr1 | result |
577577
| conversions.swift:174:13:174:13 | arr2 | conversions.swift:172:15:172:25 | call to sourceInt() | conversions.swift:174:13:174:13 | arr2 | result |
578-
| conversions.swift:175:13:175:19 | ...[...] | conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:175:13:175:19 | ...[...] | result |
578+
| conversions.swift:175:13:175:19 | ...[...] | conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:175:13:175:19 | ...[...] | result |
579579
| conversions.swift:176:13:176:19 | ...[...] | conversions.swift:172:15:172:25 | call to sourceInt() | conversions.swift:176:13:176:19 | ...[...] | result |
580-
| conversions.swift:180:13:180:13 | arr1b | conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:180:13:180:13 | arr1b | result |
580+
| conversions.swift:180:13:180:13 | arr1b | conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:180:13:180:13 | arr1b | result |
581581
| conversions.swift:181:13:181:13 | arr2b | conversions.swift:172:15:172:25 | call to sourceInt() | conversions.swift:181:13:181:13 | arr2b | result |
582-
| conversions.swift:182:13:182:20 | ...[...] | conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:182:13:182:20 | ...[...] | result |
582+
| conversions.swift:182:13:182:20 | ...[...] | conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:182:13:182:20 | ...[...] | result |
583583
| conversions.swift:183:13:183:20 | ...[...] | conversions.swift:172:15:172:25 | call to sourceInt() | conversions.swift:183:13:183:20 | ...[...] | result |
584-
| conversions.swift:187:13:187:13 | arr1c | conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:187:13:187:13 | arr1c | result |
584+
| conversions.swift:187:13:187:13 | arr1c | conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:187:13:187:13 | arr1c | result |
585585
| conversions.swift:188:13:188:13 | arr2c | conversions.swift:172:15:172:25 | call to sourceInt() | conversions.swift:188:13:188:13 | arr2c | result |
586-
| conversions.swift:189:13:189:20 | ...[...] | conversions.swift:171:14:171:26 | call to sourceArray() | conversions.swift:189:13:189:20 | ...[...] | result |
586+
| conversions.swift:189:13:189:20 | ...[...] | conversions.swift:171:14:171:33 | call to sourceArray(_:) | conversions.swift:189:13:189:20 | ...[...] | result |
587587
| conversions.swift:190:13:190:20 | ...[...] | conversions.swift:172:15:172:25 | call to sourceInt() | conversions.swift:190:13:190:20 | ...[...] | result |
588588
| simple.swift:12:13:12:24 | ... .+(_:_:) ... | simple.swift:12:17:12:24 | call to source() | simple.swift:12:13:12:24 | ... .+(_:_:) ... | result |
589589
| simple.swift:13:13:13:24 | ... .+(_:_:) ... | simple.swift:13:13:13:20 | call to source() | simple.swift:13:13:13:24 | ... .+(_:_:) ... | result |

0 commit comments

Comments
 (0)