Skip to content

Commit 1d349af

Browse files
authored
Merge pull request #22689 from michaelnebel/csharp/positionalpatternflow
C#: Data flow for positional patterns.
2 parents 2bb1fd0 + 4e4e84a commit 1d349af

6 files changed

Lines changed: 490 additions & 23 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added support for data flow through positional patterns in `is` expressions and `switch` cases.

‎csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll‎

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -563,13 +563,19 @@ module LocalFlow {
563563
exists(IsExpr e |
564564
e1 = e.getExpr() and
565565
e2 = e.getPattern() and
566-
e2 instanceof TuplePatternExpr
566+
(
567+
e2 instanceof TuplePatternExpr or
568+
e2 instanceof RecursivePatternExpr
569+
)
567570
)
568571
or
569572
exists(Switch sw |
570573
e1 = sw.getExpr() and
571574
e2 = sw.getACase().getPattern() and
572-
e2 instanceof TuplePatternExpr
575+
(
576+
e2 instanceof TuplePatternExpr or
577+
e2 instanceof RecursivePatternExpr
578+
)
573579
)
574580
}
575581

@@ -2208,6 +2214,40 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
22082214
storeStepDelegateCall(node1, c, node2)
22092215
}
22102216

2217+
private predicate readStepPattern(Node node1, Content c, Node node2) {
2218+
exists(RecursivePatternExpr pattern, PatternExpr item, int i |
2219+
node1.asExpr() = pattern and
2220+
item = pattern.getPositionalPatterns().getPattern(i) and
2221+
c.(FieldContent).getField() =
2222+
pattern.getType().(TupleType).getElement(i).getUnboundDeclaration()
2223+
|
2224+
// item = { ... } in node1 = (var ..., { ... })
2225+
item = node2.asExpr().(RecursivePatternExpr)
2226+
or
2227+
// item = (...,...) in node1 = (var ..., (..., ...))
2228+
item = node2.asExpr().(TuplePatternExpr)
2229+
or
2230+
// item = variable in node1 = (..., variable, ...) in a case/is (var ..., var ...)
2231+
exists(AssignableDefinitions::PatternDefinition lvd |
2232+
node2.(AssignableDefinitionNode).getDefinition() = lvd and
2233+
item.(BindingPatternExpr).getVariableDeclExpr() = lvd.getDeclaration()
2234+
)
2235+
)
2236+
or
2237+
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
2238+
exists(TuplePatternExpr pattern, PatternExpr item, int i |
2239+
node1.asExpr() = pattern and
2240+
c.(FieldContent).getField() =
2241+
pattern.getType().(TupleType).getElement(i).getUnboundDeclaration() and
2242+
item = pattern.getArgument(i)
2243+
|
2244+
exists(AssignableDefinitions::PatternDefinition lvd |
2245+
node2.(AssignableDefinitionNode).getDefinition() = lvd and
2246+
item = lvd.getDeclaration()
2247+
)
2248+
)
2249+
}
2250+
22112251
private predicate readContentStep(Node node1, Content c, Node node2) {
22122252
arrayRead(node1.asExpr(), node2.asExpr()) and
22132253
c instanceof ElementContent
@@ -2246,15 +2286,10 @@ private predicate readContentStep(Node node1, Content c, Node node2) {
22462286
node2.(AssignableDefinitionNode).getDefinition() = tad and
22472287
tad.getLeaf() = item
22482288
)
2249-
or
2250-
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
2251-
te instanceof TuplePatternExpr and
2252-
exists(AssignableDefinitions::PatternDefinition lvd |
2253-
node2.(AssignableDefinitionNode).getDefinition() = lvd and
2254-
lvd.getDeclaration() = item
2255-
)
22562289
)
22572290
or
2291+
readStepPattern(node1, c, node2)
2292+
or
22582293
VariableCapture::readStep(node1, c, node2)
22592294
}
22602295

‎csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected‎

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
| Tuples.cs:75:13:75:30 | SSA qualifier def(y.Item2.Item2) | Tuples.cs:80:22:80:34 | access to field Item2 |
144144
| Tuples.cs:75:17:75:30 | (..., ...) | Tuples.cs:75:13:75:13 | access to local variable y |
145145
| Tuples.cs:75:18:75:18 | access to parameter s | Tuples.cs:75:25:75:25 | access to parameter s |
146+
| Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:78:18:78:39 | { ... } |
146147
| Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:79:22:79:22 | access to local variable y |
147148
| Tuples.cs:78:19:78:23 | SSA def(a) | Tuples.cs:78:46:78:46 | access to local variable a |
148149
| Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | SSA def(a) |
@@ -226,4 +227,62 @@
226227
| Tuples.cs:133:24:133:29 | (..., ...) | Tuples.cs:133:9:133:20 | (..., ...) |
227228
| Tuples.cs:133:25:133:25 | 1 | Tuples.cs:133:9:133:29 | ... = ... |
228229
| Tuples.cs:133:28:133:28 | access to local variable o | Tuples.cs:133:18:133:19 | access to local variable y4 |
229-
| Tuples.cs:144:18:144:31 | this | Tuples.cs:144:18:144:31 | this access |
230+
| Tuples.cs:139:13:139:14 | access to local variable o1 | Tuples.cs:139:13:139:35 | SSA def(o1) |
231+
| Tuples.cs:139:13:139:35 | SSA def(o1) | Tuples.cs:141:18:141:19 | access to local variable o1 |
232+
| Tuples.cs:139:18:139:35 | call to method Source<String> | Tuples.cs:139:13:139:14 | access to local variable o1 |
233+
| Tuples.cs:139:33:139:34 | 10 | Tuples.cs:139:33:139:34 | (...) ... |
234+
| Tuples.cs:140:13:140:14 | access to local variable o2 | Tuples.cs:140:13:140:35 | SSA def(o2) |
235+
| Tuples.cs:140:13:140:35 | SSA def(o2) | Tuples.cs:141:26:141:27 | access to local variable o2 |
236+
| Tuples.cs:140:18:140:35 | call to method Source<String> | Tuples.cs:140:13:140:14 | access to local variable o2 |
237+
| Tuples.cs:140:33:140:34 | 11 | Tuples.cs:140:33:140:34 | (...) ... |
238+
| Tuples.cs:141:13:141:13 | access to local variable x | Tuples.cs:141:13:141:32 | SSA def(x) |
239+
| Tuples.cs:141:13:141:32 | SSA def(x) | Tuples.cs:142:17:142:17 | access to local variable x |
240+
| Tuples.cs:141:17:141:32 | (..., ...) | Tuples.cs:141:13:141:13 | access to local variable x |
241+
| Tuples.cs:142:17:142:17 | access to local variable x | Tuples.cs:144:18:144:46 | { ... } |
242+
| Tuples.cs:144:19:144:24 | SSA def(a1) | Tuples.cs:145:22:145:23 | access to local variable a1 |
243+
| Tuples.cs:144:19:144:24 | String a1 | Tuples.cs:144:19:144:24 | SSA def(a1) |
244+
| Tuples.cs:144:28:144:33 | Int32 b1 | Tuples.cs:144:28:144:33 | SSA def(b1) |
245+
| Tuples.cs:144:28:144:33 | SSA def(b1) | Tuples.cs:147:22:147:23 | access to local variable b1 |
246+
| Tuples.cs:144:36:144:41 | SSA def(c1) | Tuples.cs:146:22:146:23 | access to local variable c1 |
247+
| Tuples.cs:144:36:144:41 | String c1 | Tuples.cs:144:36:144:41 | SSA def(c1) |
248+
| Tuples.cs:147:22:147:23 | access to local variable b1 | Tuples.cs:147:22:147:23 | (...) ... |
249+
| Tuples.cs:151:13:151:14 | access to local variable o3 | Tuples.cs:151:13:151:35 | SSA def(o3) |
250+
| Tuples.cs:151:13:151:35 | SSA def(o3) | Tuples.cs:153:18:153:19 | access to local variable o3 |
251+
| Tuples.cs:151:18:151:35 | call to method Source<String> | Tuples.cs:151:13:151:14 | access to local variable o3 |
252+
| Tuples.cs:151:33:151:34 | 12 | Tuples.cs:151:33:151:34 | (...) ... |
253+
| Tuples.cs:152:13:152:14 | access to local variable o4 | Tuples.cs:152:13:152:35 | SSA def(o4) |
254+
| Tuples.cs:152:13:152:35 | SSA def(o4) | Tuples.cs:153:26:153:27 | access to local variable o4 |
255+
| Tuples.cs:152:18:152:35 | call to method Source<String> | Tuples.cs:152:13:152:14 | access to local variable o4 |
256+
| Tuples.cs:152:33:152:34 | 13 | Tuples.cs:152:33:152:34 | (...) ... |
257+
| Tuples.cs:153:13:153:13 | access to local variable y | Tuples.cs:153:13:153:32 | SSA def(y) |
258+
| Tuples.cs:153:13:153:32 | SSA def(y) | Tuples.cs:154:13:154:13 | access to local variable y |
259+
| Tuples.cs:153:17:153:32 | (..., ...) | Tuples.cs:153:13:153:13 | access to local variable y |
260+
| Tuples.cs:154:13:154:13 | access to local variable y | Tuples.cs:154:18:154:42 | { ... } |
261+
| Tuples.cs:154:19:154:24 | SSA def(a2) | Tuples.cs:156:18:156:19 | access to local variable a2 |
262+
| Tuples.cs:154:19:154:24 | String a2 | Tuples.cs:154:19:154:24 | SSA def(a2) |
263+
| Tuples.cs:154:32:154:33 | Int32 b2 | Tuples.cs:154:32:154:33 | SSA def(b2) |
264+
| Tuples.cs:154:32:154:33 | SSA def(b2) | Tuples.cs:158:18:158:19 | access to local variable b2 |
265+
| Tuples.cs:154:36:154:37 | SSA def(c2) | Tuples.cs:157:18:157:19 | access to local variable c2 |
266+
| Tuples.cs:154:36:154:37 | String c2 | Tuples.cs:154:36:154:37 | SSA def(c2) |
267+
| Tuples.cs:158:18:158:19 | access to local variable b2 | Tuples.cs:158:18:158:19 | (...) ... |
268+
| Tuples.cs:161:13:161:14 | access to local variable o5 | Tuples.cs:161:13:161:35 | SSA def(o5) |
269+
| Tuples.cs:161:13:161:35 | SSA def(o5) | Tuples.cs:163:18:163:19 | access to local variable o5 |
270+
| Tuples.cs:161:18:161:35 | call to method Source<String> | Tuples.cs:161:13:161:14 | access to local variable o5 |
271+
| Tuples.cs:161:33:161:34 | 14 | Tuples.cs:161:33:161:34 | (...) ... |
272+
| Tuples.cs:162:13:162:14 | access to local variable o6 | Tuples.cs:162:13:162:35 | SSA def(o6) |
273+
| Tuples.cs:162:13:162:35 | SSA def(o6) | Tuples.cs:163:26:163:27 | access to local variable o6 |
274+
| Tuples.cs:162:18:162:35 | call to method Source<String> | Tuples.cs:162:13:162:14 | access to local variable o6 |
275+
| Tuples.cs:162:33:162:34 | 15 | Tuples.cs:162:33:162:34 | (...) ... |
276+
| Tuples.cs:163:13:163:13 | access to local variable z | Tuples.cs:163:13:163:32 | SSA def(z) |
277+
| Tuples.cs:163:13:163:32 | SSA def(z) | Tuples.cs:164:13:164:13 | access to local variable z |
278+
| Tuples.cs:163:17:163:32 | (..., ...) | Tuples.cs:163:13:163:13 | access to local variable z |
279+
| Tuples.cs:164:13:164:13 | access to local variable z | Tuples.cs:164:18:164:47 | { ... } |
280+
| Tuples.cs:164:19:164:24 | SSA def(a3) | Tuples.cs:166:18:166:19 | access to local variable a3 |
281+
| Tuples.cs:164:19:164:24 | String a3 | Tuples.cs:164:19:164:24 | SSA def(a3) |
282+
| Tuples.cs:164:27:164:43 | (Int32,String) t | Tuples.cs:164:27:164:43 | SSA def(t) |
283+
| Tuples.cs:164:27:164:43 | SSA def(t) | Tuples.cs:167:18:167:18 | access to local variable t |
284+
| Tuples.cs:164:27:164:43 | SSA qualifier def(t.Item2) | Tuples.cs:167:18:167:24 | access to field Item2 |
285+
| Tuples.cs:164:28:164:33 | Int32 b3 | Tuples.cs:164:28:164:33 | SSA def(b3) |
286+
| Tuples.cs:164:28:164:33 | SSA def(b3) | Tuples.cs:168:18:168:19 | access to local variable b3 |
287+
| Tuples.cs:168:18:168:19 | access to local variable b3 | Tuples.cs:168:18:168:19 | (...) ... |
288+
| Tuples.cs:179:18:179:31 | this | Tuples.cs:179:18:179:31 | this access |

‎csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected‎

Lines changed: 155 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -504,20 +504,162 @@ Tuples.cs:
504504
# 134| 12: [ExprStmt] ...;
505505
# 134| 0: [MethodCall] call to method Sink
506506
# 134| 0: [LocalVariableAccess] access to local variable y4
507-
# 137| 13: [Method] Sink
507+
# 137| 13: [Method] M7
508508
# 137| -1: [TypeMention] Void
509+
# 138| 4: [BlockStmt] {...}
510+
# 139| 0: [LocalVariableDeclStmt] ... ...;
511+
# 139| 0: [LocalVariableDeclAndInitExpr] String o1 = ...
512+
# 139| -1: [TypeMention] string
513+
# 139| 0: [LocalVariableAccess] access to local variable o1
514+
# 139| 1: [MethodCall] call to method Source<String>
515+
# 139| 0: [CastExpr] (...) ...
516+
# 139| 1: [IntLiteral] 10
517+
# 140| 1: [LocalVariableDeclStmt] ... ...;
518+
# 140| 0: [LocalVariableDeclAndInitExpr] String o2 = ...
519+
# 140| -1: [TypeMention] string
520+
# 140| 0: [LocalVariableAccess] access to local variable o2
521+
# 140| 1: [MethodCall] call to method Source<String>
522+
# 140| 0: [CastExpr] (...) ...
523+
# 140| 1: [IntLiteral] 11
524+
# 141| 2: [LocalVariableDeclStmt] ... ...;
525+
# 141| 0: [LocalVariableDeclAndInitExpr] (String,(Int32,String),Int32) x = ...
526+
# 141| -1: [TypeMention] (string, (int, string), int)
527+
# 141| 0: [LocalVariableAccess] access to local variable x
528+
# 141| 1: [TupleExpr] (..., ...)
529+
# 141| 0: [LocalVariableAccess] access to local variable o1
530+
# 141| 1: [TupleExpr] (..., ...)
531+
# 141| 0: [IntLiteral] 2
532+
# 141| 1: [LocalVariableAccess] access to local variable o2
533+
# 141| 2: [IntLiteral] 3
534+
# 142| 3: [SwitchStmt] switch (...) {...}
535+
# 142| 0: [LocalVariableAccess] access to local variable x
536+
# 144| 0: [CaseStmt] case ...:
537+
# 144| 0: [RecursivePatternExpr] { ... }
538+
# 144| 2: [PositionalPatternExpr] ( ... )
539+
# 144| 0: [VariablePatternExpr] String a1
540+
# 144| 1: [RecursivePatternExpr] { ... }
541+
# 144| 2: [PositionalPatternExpr] ( ... )
542+
# 144| 0: [VariablePatternExpr] Int32 b1
543+
# 144| 1: [VariablePatternExpr] String c1
544+
# 144| 2: [DiscardPatternExpr] _
545+
# 145| 1: [ExprStmt] ...;
546+
# 145| 0: [MethodCall] call to method Sink
547+
# 145| 0: [LocalVariableAccess] access to local variable a1
548+
# 146| 2: [ExprStmt] ...;
549+
# 146| 0: [MethodCall] call to method Sink
550+
# 146| 0: [LocalVariableAccess] access to local variable c1
551+
# 147| 3: [ExprStmt] ...;
552+
# 147| 0: [MethodCall] call to method Sink
553+
# 147| 0: [CastExpr] (...) ...
554+
# 147| 1: [LocalVariableAccess] access to local variable b1
555+
# 148| 4: [BreakStmt] break;
556+
# 151| 4: [LocalVariableDeclStmt] ... ...;
557+
# 151| 0: [LocalVariableDeclAndInitExpr] String o3 = ...
558+
# 151| -1: [TypeMention] string
559+
# 151| 0: [LocalVariableAccess] access to local variable o3
560+
# 151| 1: [MethodCall] call to method Source<String>
561+
# 151| 0: [CastExpr] (...) ...
562+
# 151| 1: [IntLiteral] 12
563+
# 152| 5: [LocalVariableDeclStmt] ... ...;
564+
# 152| 0: [LocalVariableDeclAndInitExpr] String o4 = ...
565+
# 152| -1: [TypeMention] string
566+
# 152| 0: [LocalVariableAccess] access to local variable o4
567+
# 152| 1: [MethodCall] call to method Source<String>
568+
# 152| 0: [CastExpr] (...) ...
569+
# 152| 1: [IntLiteral] 13
570+
# 153| 6: [LocalVariableDeclStmt] ... ...;
571+
# 153| 0: [LocalVariableDeclAndInitExpr] (String,(Int32,String),Int32) y = ...
572+
# 153| -1: [TypeMention] (string, (int, string), int)
573+
# 153| 0: [LocalVariableAccess] access to local variable y
574+
# 153| 1: [TupleExpr] (..., ...)
575+
# 153| 0: [LocalVariableAccess] access to local variable o3
576+
# 153| 1: [TupleExpr] (..., ...)
577+
# 153| 0: [IntLiteral] 2
578+
# 153| 1: [LocalVariableAccess] access to local variable o4
579+
# 153| 2: [IntLiteral] 3
580+
# 154| 7: [IfStmt] if (...) ...
581+
# 154| 0: [IsExpr] ... is ...
582+
# 154| 0: [LocalVariableAccess] access to local variable y
583+
# 154| 1: [RecursivePatternExpr] { ... }
584+
# 154| 2: [PositionalPatternExpr] ( ... )
585+
# 154| 0: [VariablePatternExpr] String a2
586+
# 154| 1: [TuplePatternExpr] (..., ...)
587+
# 154| 0: [VariablePatternExpr] Int32 b2
588+
# 154| 1: [VariablePatternExpr] String c2
589+
# 154| 2: [DiscardPatternExpr] _
590+
# 155| 1: [BlockStmt] {...}
591+
# 156| 0: [ExprStmt] ...;
592+
# 156| 0: [MethodCall] call to method Sink
593+
# 156| 0: [LocalVariableAccess] access to local variable a2
594+
# 157| 1: [ExprStmt] ...;
595+
# 157| 0: [MethodCall] call to method Sink
596+
# 157| 0: [LocalVariableAccess] access to local variable c2
597+
# 158| 2: [ExprStmt] ...;
598+
# 158| 0: [MethodCall] call to method Sink
599+
# 158| 0: [CastExpr] (...) ...
600+
# 158| 1: [LocalVariableAccess] access to local variable b2
601+
# 161| 8: [LocalVariableDeclStmt] ... ...;
602+
# 161| 0: [LocalVariableDeclAndInitExpr] String o5 = ...
603+
# 161| -1: [TypeMention] string
604+
# 161| 0: [LocalVariableAccess] access to local variable o5
605+
# 161| 1: [MethodCall] call to method Source<String>
606+
# 161| 0: [CastExpr] (...) ...
607+
# 161| 1: [IntLiteral] 14
608+
# 162| 9: [LocalVariableDeclStmt] ... ...;
609+
# 162| 0: [LocalVariableDeclAndInitExpr] String o6 = ...
610+
# 162| -1: [TypeMention] string
611+
# 162| 0: [LocalVariableAccess] access to local variable o6
612+
# 162| 1: [MethodCall] call to method Source<String>
613+
# 162| 0: [CastExpr] (...) ...
614+
# 162| 1: [IntLiteral] 15
615+
# 163| 10: [LocalVariableDeclStmt] ... ...;
616+
# 163| 0: [LocalVariableDeclAndInitExpr] (String,(Int32,String),Int32) z = ...
617+
# 163| -1: [TypeMention] (string, (int, string), int)
618+
# 163| 0: [LocalVariableAccess] access to local variable z
619+
# 163| 1: [TupleExpr] (..., ...)
620+
# 163| 0: [LocalVariableAccess] access to local variable o5
621+
# 163| 1: [TupleExpr] (..., ...)
622+
# 163| 0: [IntLiteral] 2
623+
# 163| 1: [LocalVariableAccess] access to local variable o6
624+
# 163| 2: [IntLiteral] 3
625+
# 164| 11: [IfStmt] if (...) ...
626+
# 164| 0: [IsExpr] ... is ...
627+
# 164| 0: [LocalVariableAccess] access to local variable z
628+
# 164| 1: [RecursivePatternExpr] { ... }
629+
# 164| 2: [PositionalPatternExpr] ( ... )
630+
# 164| 0: [VariablePatternExpr] String a3
631+
# 164| 1: [RecursivePatternExpr] { ... }
632+
# 164| 0: [VariablePatternExpr] (Int32,String) t
633+
# 164| 2: [PositionalPatternExpr] ( ... )
634+
# 164| 0: [VariablePatternExpr] Int32 b3
635+
# 164| 1: [DiscardPatternExpr] _
636+
# 164| 2: [DiscardPatternExpr] _
637+
# 165| 1: [BlockStmt] {...}
638+
# 166| 0: [ExprStmt] ...;
639+
# 166| 0: [MethodCall] call to method Sink
640+
# 166| 0: [LocalVariableAccess] access to local variable a3
641+
# 167| 1: [ExprStmt] ...;
642+
# 167| 0: [MethodCall] call to method Sink
643+
# 167| 0: [FieldAccess] access to field Item2
644+
# 167| -1: [LocalVariableAccess] access to local variable t
645+
# 168| 2: [ExprStmt] ...;
646+
# 168| 0: [MethodCall] call to method Sink
647+
# 168| 0: [CastExpr] (...) ...
648+
# 168| 1: [LocalVariableAccess] access to local variable b3
649+
# 172| 14: [Method] Sink
650+
# 172| -1: [TypeMention] Void
509651
#-----| 2: (Parameters)
510-
# 137| 0: [Parameter] o
511-
# 137| -1: [TypeMention] object
512-
# 137| 4: [BlockStmt] {...}
513-
# 139| 16: [Method] Source`1
514-
# 139| -1: [TypeMention] T
652+
# 172| 0: [Parameter] o
653+
# 172| -1: [TypeMention] object
654+
# 172| 4: [BlockStmt] {...}
655+
# 174| 17: [Method] Source`1
656+
# 174| -1: [TypeMention] T
515657
#-----| 1: (Type parameters)
516-
# 139| 0: [TypeParameter] T
658+
# 174| 0: [TypeParameter] T
517659
#-----| 2: (Parameters)
518-
# 139| 0: [Parameter] source
519-
# 139| -1: [TypeMention] object
520-
# 139| 4: [ThrowExpr] throw ...
521-
# 139| 0: [NullLiteral] null
522-
# 142| [NamespaceDeclaration] namespace ... { ... }
523-
# 144| 1: [Class] IsExternalInit
660+
# 174| 0: [Parameter] source
661+
# 174| -1: [TypeMention] object
662+
# 174| 4: [ThrowExpr] throw ...
663+
# 174| 0: [NullLiteral] null
664+
# 177| [NamespaceDeclaration] namespace ... { ... }
665+
# 179| 1: [Class] IsExternalInit

‎csharp/ql/test/library-tests/dataflow/tuples/Tuples.cs‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,41 @@ static void M6()
134134
Sink(y4); // $ hasValueFlow=9
135135
}
136136

137+
static void M7()
138+
{
139+
var o1 = Source<string>(10);
140+
var o2 = Source<string>(11);
141+
var x = (o1, (2, o2), 3);
142+
switch (x)
143+
{
144+
case (var a1, (var b1, var c1), _):
145+
Sink(a1); // $ hasValueFlow=10
146+
Sink(c1); // $ hasValueFlow=11
147+
Sink(b1);
148+
break;
149+
}
150+
151+
var o3 = Source<string>(12);
152+
var o4 = Source<string>(13);
153+
var y = (o3, (2, o4), 3);
154+
if (y is (var a2, var (b2, c2), _))
155+
{
156+
Sink(a2); // $ hasValueFlow=12
157+
Sink(c2); // $ hasValueFlow=13
158+
Sink(b2);
159+
}
160+
161+
var o5 = Source<string>(14);
162+
var o6 = Source<string>(15);
163+
var z = (o5, (2, o6), 3);
164+
if (z is (var a3, (var b3, var _) t, _))
165+
{
166+
Sink(a3); // $ hasValueFlow=14
167+
Sink(t.Item2); // $ hasValueFlow=15
168+
Sink(b3);
169+
}
170+
}
171+
137172
public static void Sink(object o) { }
138173

139174
static T Source<T>(object source) => throw null;

0 commit comments

Comments
 (0)