diff --git a/csharp/ql/lib/change-notes/2026-10-02-positional-pattern-flow.md b/csharp/ql/lib/change-notes/2026-10-02-positional-pattern-flow.md new file mode 100644 index 000000000000..82ab7335aa2f --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-10-02-positional-pattern-flow.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for data flow through positional patterns in `is` expressions and `switch` cases. diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index a89c06a0bf25..777d46f1c82a 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -563,13 +563,19 @@ module LocalFlow { exists(IsExpr e | e1 = e.getExpr() and e2 = e.getPattern() and - e2 instanceof TuplePatternExpr + ( + e2 instanceof TuplePatternExpr or + e2 instanceof RecursivePatternExpr + ) ) or exists(Switch sw | e1 = sw.getExpr() and e2 = sw.getACase().getPattern() and - e2 instanceof TuplePatternExpr + ( + e2 instanceof TuplePatternExpr or + e2 instanceof RecursivePatternExpr + ) ) } @@ -2208,6 +2214,40 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepDelegateCall(node1, c, node2) } +private predicate readStepPattern(Node node1, Content c, Node node2) { + exists(RecursivePatternExpr pattern, PatternExpr item, int i | + node1.asExpr() = pattern and + item = pattern.getPositionalPatterns().getPattern(i) and + c.(FieldContent).getField() = + pattern.getType().(TupleType).getElement(i).getUnboundDeclaration() + | + // item = { ... } in node1 = (var ..., { ... }) + item = node2.asExpr().(RecursivePatternExpr) + or + // item = (...,...) in node1 = (var ..., (..., ...)) + item = node2.asExpr().(TuplePatternExpr) + or + // item = variable in node1 = (..., variable, ...) in a case/is (var ..., var ...) + exists(AssignableDefinitions::PatternDefinition lvd | + node2.(AssignableDefinitionNode).getDefinition() = lvd and + item = lvd.getDeclaration() + ) + ) + or + // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) + exists(TuplePatternExpr pattern, PatternExpr item, int i | + node1.asExpr() = pattern and + c.(FieldContent).getField() = + pattern.getType().(TupleType).getElement(i).getUnboundDeclaration() and + item = pattern.getArgument(i) + | + exists(AssignableDefinitions::PatternDefinition lvd | + node2.(AssignableDefinitionNode).getDefinition() = lvd and + item = lvd.getDeclaration() + ) + ) +} + private predicate readContentStep(Node node1, Content c, Node node2) { arrayRead(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent @@ -2246,15 +2286,10 @@ private predicate readContentStep(Node node1, Content c, Node node2) { node2.(AssignableDefinitionNode).getDefinition() = tad and tad.getLeaf() = item ) - or - // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) - te instanceof TuplePatternExpr and - exists(AssignableDefinitions::PatternDefinition lvd | - node2.(AssignableDefinitionNode).getDefinition() = lvd and - lvd.getDeclaration() = item - ) ) or + readStepPattern(node1, c, node2) + or VariableCapture::readStep(node1, c, node2) } diff --git a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected index e4ccec569202..dc51b6906c5e 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected @@ -143,6 +143,7 @@ | Tuples.cs:75:13:75:30 | SSA qualifier def(y.Item2.Item2) | Tuples.cs:80:22:80:34 | access to field Item2 | | Tuples.cs:75:17:75:30 | (..., ...) | Tuples.cs:75:13:75:13 | access to local variable y | | Tuples.cs:75:18:75:18 | access to parameter s | Tuples.cs:75:25:75:25 | access to parameter s | +| Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:78:18:78:39 | { ... } | | Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:79:22:79:22 | access to local variable y | | Tuples.cs:78:19:78:23 | SSA def(a) | Tuples.cs:78:46:78:46 | access to local variable a | | Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | SSA def(a) | @@ -226,4 +227,42 @@ | Tuples.cs:133:24:133:29 | (..., ...) | Tuples.cs:133:9:133:20 | (..., ...) | | Tuples.cs:133:25:133:25 | 1 | Tuples.cs:133:9:133:29 | ... = ... | | Tuples.cs:133:28:133:28 | access to local variable o | Tuples.cs:133:18:133:19 | access to local variable y4 | -| Tuples.cs:144:18:144:31 | this | Tuples.cs:144:18:144:31 | this access | +| Tuples.cs:139:13:139:14 | access to local variable o1 | Tuples.cs:139:13:139:35 | SSA def(o1) | +| Tuples.cs:139:13:139:35 | SSA def(o1) | Tuples.cs:141:18:141:19 | access to local variable o1 | +| Tuples.cs:139:18:139:35 | call to method Source | Tuples.cs:139:13:139:14 | access to local variable o1 | +| Tuples.cs:139:33:139:34 | 10 | Tuples.cs:139:33:139:34 | (...) ... | +| Tuples.cs:140:13:140:14 | access to local variable o2 | Tuples.cs:140:13:140:35 | SSA def(o2) | +| Tuples.cs:140:13:140:35 | SSA def(o2) | Tuples.cs:141:26:141:27 | access to local variable o2 | +| Tuples.cs:140:18:140:35 | call to method Source | Tuples.cs:140:13:140:14 | access to local variable o2 | +| Tuples.cs:140:33:140:34 | 11 | Tuples.cs:140:33:140:34 | (...) ... | +| Tuples.cs:141:13:141:13 | access to local variable x | Tuples.cs:141:13:141:32 | SSA def(x) | +| Tuples.cs:141:13:141:32 | SSA def(x) | Tuples.cs:142:17:142:17 | access to local variable x | +| Tuples.cs:141:17:141:32 | (..., ...) | Tuples.cs:141:13:141:13 | access to local variable x | +| Tuples.cs:142:17:142:17 | access to local variable x | Tuples.cs:144:18:144:46 | { ... } | +| Tuples.cs:144:19:144:24 | SSA def(a1) | Tuples.cs:145:22:145:23 | access to local variable a1 | +| Tuples.cs:144:19:144:24 | String a1 | Tuples.cs:144:19:144:24 | SSA def(a1) | +| Tuples.cs:144:28:144:33 | Int32 b1 | Tuples.cs:144:28:144:33 | SSA def(b1) | +| Tuples.cs:144:28:144:33 | SSA def(b1) | Tuples.cs:147:22:147:23 | access to local variable b1 | +| Tuples.cs:144:36:144:41 | SSA def(c1) | Tuples.cs:146:22:146:23 | access to local variable c1 | +| Tuples.cs:144:36:144:41 | String c1 | Tuples.cs:144:36:144:41 | SSA def(c1) | +| Tuples.cs:147:22:147:23 | access to local variable b1 | Tuples.cs:147:22:147:23 | (...) ... | +| Tuples.cs:151:13:151:14 | access to local variable o3 | Tuples.cs:151:13:151:35 | SSA def(o3) | +| Tuples.cs:151:13:151:35 | SSA def(o3) | Tuples.cs:153:18:153:19 | access to local variable o3 | +| Tuples.cs:151:18:151:35 | call to method Source | Tuples.cs:151:13:151:14 | access to local variable o3 | +| Tuples.cs:151:33:151:34 | 12 | Tuples.cs:151:33:151:34 | (...) ... | +| Tuples.cs:152:13:152:14 | access to local variable o4 | Tuples.cs:152:13:152:35 | SSA def(o4) | +| Tuples.cs:152:13:152:35 | SSA def(o4) | Tuples.cs:153:26:153:27 | access to local variable o4 | +| Tuples.cs:152:18:152:35 | call to method Source | Tuples.cs:152:13:152:14 | access to local variable o4 | +| Tuples.cs:152:33:152:34 | 13 | Tuples.cs:152:33:152:34 | (...) ... | +| Tuples.cs:153:13:153:13 | access to local variable y | Tuples.cs:153:13:153:32 | SSA def(y) | +| Tuples.cs:153:13:153:32 | SSA def(y) | Tuples.cs:154:13:154:13 | access to local variable y | +| Tuples.cs:153:17:153:32 | (..., ...) | Tuples.cs:153:13:153:13 | access to local variable y | +| Tuples.cs:154:13:154:13 | access to local variable y | Tuples.cs:154:18:154:42 | { ... } | +| Tuples.cs:154:19:154:24 | SSA def(a2) | Tuples.cs:156:18:156:19 | access to local variable a2 | +| Tuples.cs:154:19:154:24 | String a2 | Tuples.cs:154:19:154:24 | SSA def(a2) | +| Tuples.cs:154:32:154:33 | Int32 b2 | Tuples.cs:154:32:154:33 | SSA def(b2) | +| Tuples.cs:154:32:154:33 | SSA def(b2) | Tuples.cs:158:18:158:19 | access to local variable b2 | +| Tuples.cs:154:36:154:37 | SSA def(c2) | Tuples.cs:157:18:157:19 | access to local variable c2 | +| Tuples.cs:154:36:154:37 | String c2 | Tuples.cs:154:36:154:37 | SSA def(c2) | +| Tuples.cs:158:18:158:19 | access to local variable b2 | Tuples.cs:158:18:158:19 | (...) ... | +| Tuples.cs:169:18:169:31 | this | Tuples.cs:169:18:169:31 | this access | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected b/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected index c7416e3c874e..0ced4d088953 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected @@ -504,20 +504,114 @@ Tuples.cs: # 134| 12: [ExprStmt] ...; # 134| 0: [MethodCall] call to method Sink # 134| 0: [LocalVariableAccess] access to local variable y4 -# 137| 13: [Method] Sink +# 137| 13: [Method] M7 # 137| -1: [TypeMention] Void +# 138| 4: [BlockStmt] {...} +# 139| 0: [LocalVariableDeclStmt] ... ...; +# 139| 0: [LocalVariableDeclAndInitExpr] String o1 = ... +# 139| -1: [TypeMention] string +# 139| 0: [LocalVariableAccess] access to local variable o1 +# 139| 1: [MethodCall] call to method Source +# 139| 0: [CastExpr] (...) ... +# 139| 1: [IntLiteral] 10 +# 140| 1: [LocalVariableDeclStmt] ... ...; +# 140| 0: [LocalVariableDeclAndInitExpr] String o2 = ... +# 140| -1: [TypeMention] string +# 140| 0: [LocalVariableAccess] access to local variable o2 +# 140| 1: [MethodCall] call to method Source +# 140| 0: [CastExpr] (...) ... +# 140| 1: [IntLiteral] 11 +# 141| 2: [LocalVariableDeclStmt] ... ...; +# 141| 0: [LocalVariableDeclAndInitExpr] (String,(Int32,String),Int32) x = ... +# 141| -1: [TypeMention] (string, (int, string), int) +# 141| 0: [LocalVariableAccess] access to local variable x +# 141| 1: [TupleExpr] (..., ...) +# 141| 0: [LocalVariableAccess] access to local variable o1 +# 141| 1: [TupleExpr] (..., ...) +# 141| 0: [IntLiteral] 2 +# 141| 1: [LocalVariableAccess] access to local variable o2 +# 141| 2: [IntLiteral] 3 +# 142| 3: [SwitchStmt] switch (...) {...} +# 142| 0: [LocalVariableAccess] access to local variable x +# 144| 0: [CaseStmt] case ...: +# 144| 0: [RecursivePatternExpr] { ... } +# 144| 2: [PositionalPatternExpr] ( ... ) +# 144| 0: [VariablePatternExpr] String a1 +# 144| 1: [RecursivePatternExpr] { ... } +# 144| 2: [PositionalPatternExpr] ( ... ) +# 144| 0: [VariablePatternExpr] Int32 b1 +# 144| 1: [VariablePatternExpr] String c1 +# 144| 2: [DiscardPatternExpr] _ +# 145| 1: [ExprStmt] ...; +# 145| 0: [MethodCall] call to method Sink +# 145| 0: [LocalVariableAccess] access to local variable a1 +# 146| 2: [ExprStmt] ...; +# 146| 0: [MethodCall] call to method Sink +# 146| 0: [LocalVariableAccess] access to local variable c1 +# 147| 3: [ExprStmt] ...; +# 147| 0: [MethodCall] call to method Sink +# 147| 0: [CastExpr] (...) ... +# 147| 1: [LocalVariableAccess] access to local variable b1 +# 148| 4: [BreakStmt] break; +# 151| 4: [LocalVariableDeclStmt] ... ...; +# 151| 0: [LocalVariableDeclAndInitExpr] String o3 = ... +# 151| -1: [TypeMention] string +# 151| 0: [LocalVariableAccess] access to local variable o3 +# 151| 1: [MethodCall] call to method Source +# 151| 0: [CastExpr] (...) ... +# 151| 1: [IntLiteral] 12 +# 152| 5: [LocalVariableDeclStmt] ... ...; +# 152| 0: [LocalVariableDeclAndInitExpr] String o4 = ... +# 152| -1: [TypeMention] string +# 152| 0: [LocalVariableAccess] access to local variable o4 +# 152| 1: [MethodCall] call to method Source +# 152| 0: [CastExpr] (...) ... +# 152| 1: [IntLiteral] 13 +# 153| 6: [LocalVariableDeclStmt] ... ...; +# 153| 0: [LocalVariableDeclAndInitExpr] (String,(Int32,String),Int32) y = ... +# 153| -1: [TypeMention] (string, (int, string), int) +# 153| 0: [LocalVariableAccess] access to local variable y +# 153| 1: [TupleExpr] (..., ...) +# 153| 0: [LocalVariableAccess] access to local variable o3 +# 153| 1: [TupleExpr] (..., ...) +# 153| 0: [IntLiteral] 2 +# 153| 1: [LocalVariableAccess] access to local variable o4 +# 153| 2: [IntLiteral] 3 +# 154| 7: [IfStmt] if (...) ... +# 154| 0: [IsExpr] ... is ... +# 154| 0: [LocalVariableAccess] access to local variable y +# 154| 1: [RecursivePatternExpr] { ... } +# 154| 2: [PositionalPatternExpr] ( ... ) +# 154| 0: [VariablePatternExpr] String a2 +# 154| 1: [TuplePatternExpr] (..., ...) +# 154| 0: [VariablePatternExpr] Int32 b2 +# 154| 1: [VariablePatternExpr] String c2 +# 154| 2: [DiscardPatternExpr] _ +# 155| 1: [BlockStmt] {...} +# 156| 0: [ExprStmt] ...; +# 156| 0: [MethodCall] call to method Sink +# 156| 0: [LocalVariableAccess] access to local variable a2 +# 157| 1: [ExprStmt] ...; +# 157| 0: [MethodCall] call to method Sink +# 157| 0: [LocalVariableAccess] access to local variable c2 +# 158| 2: [ExprStmt] ...; +# 158| 0: [MethodCall] call to method Sink +# 158| 0: [CastExpr] (...) ... +# 158| 1: [LocalVariableAccess] access to local variable b2 +# 162| 14: [Method] Sink +# 162| -1: [TypeMention] Void #-----| 2: (Parameters) -# 137| 0: [Parameter] o -# 137| -1: [TypeMention] object -# 137| 4: [BlockStmt] {...} -# 139| 16: [Method] Source`1 -# 139| -1: [TypeMention] T +# 162| 0: [Parameter] o +# 162| -1: [TypeMention] object +# 162| 4: [BlockStmt] {...} +# 164| 17: [Method] Source`1 +# 164| -1: [TypeMention] T #-----| 1: (Type parameters) -# 139| 0: [TypeParameter] T +# 164| 0: [TypeParameter] T #-----| 2: (Parameters) -# 139| 0: [Parameter] source -# 139| -1: [TypeMention] object -# 139| 4: [ThrowExpr] throw ... -# 139| 0: [NullLiteral] null -# 142| [NamespaceDeclaration] namespace ... { ... } -# 144| 1: [Class] IsExternalInit +# 164| 0: [Parameter] source +# 164| -1: [TypeMention] object +# 164| 4: [ThrowExpr] throw ... +# 164| 0: [NullLiteral] null +# 167| [NamespaceDeclaration] namespace ... { ... } +# 169| 1: [Class] IsExternalInit diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.cs b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.cs index 9566f7c70d6a..ab1d07a114b4 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.cs +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.cs @@ -134,6 +134,31 @@ static void M6() Sink(y4); // $ hasValueFlow=9 } + static void M7() + { + var o1 = Source(10); + var o2 = Source(11); + var x = (o1, (2, o2), 3); + switch (x) + { + case (var a1, (var b1, var c1), _): + Sink(a1); // $ hasValueFlow=10 + Sink(c1); // $ hasValueFlow=11 + Sink(b1); + break; + } + + var o3 = Source(12); + var o4 = Source(13); + var y = (o3, (2, o4), 3); + if (y is (var a2, var (b2, c2), _)) + { + Sink(a2); // $ hasValueFlow=12 + Sink(c2); // $ hasValueFlow=13 + Sink(b2); + } + } + public static void Sink(object o) { } static T Source(object source) => throw null; diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected index 41ea12890262..491d4eb73be4 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected @@ -214,6 +214,62 @@ edges | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | provenance | | | Tuples.cs:133:28:133:28 | access to local variable o : Object | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | provenance | | | Tuples.cs:133:28:133:28 | access to local variable o : Object | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | provenance | | +| Tuples.cs:139:13:139:14 | access to local variable o1 : String | Tuples.cs:141:18:141:19 | access to local variable o1 : String | provenance | | +| Tuples.cs:139:13:139:14 | access to local variable o1 : String | Tuples.cs:141:18:141:19 | access to local variable o1 : String | provenance | | +| Tuples.cs:139:18:139:35 | call to method Source : String | Tuples.cs:139:13:139:14 | access to local variable o1 : String | provenance | | +| Tuples.cs:139:18:139:35 | call to method Source : String | Tuples.cs:139:13:139:14 | access to local variable o1 : String | provenance | | +| Tuples.cs:140:13:140:14 | access to local variable o2 : String | Tuples.cs:141:26:141:27 | access to local variable o2 : String | provenance | | +| Tuples.cs:140:13:140:14 | access to local variable o2 : String | Tuples.cs:141:26:141:27 | access to local variable o2 : String | provenance | | +| Tuples.cs:140:18:140:35 | call to method Source : String | Tuples.cs:140:13:140:14 | access to local variable o2 : String | provenance | | +| Tuples.cs:140:18:140:35 | call to method Source : String | Tuples.cs:140:13:140:14 | access to local variable o2 : String | provenance | | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item1] : String | Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item1] : String | Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:141:18:141:19 | access to local variable o1 : String | Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:141:18:141:19 | access to local variable o1 : String | Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:141:22:141:28 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:141:22:141:28 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:141:26:141:27 | access to local variable o2 : String | Tuples.cs:141:22:141:28 | (..., ...) : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:141:26:141:27 | access to local variable o2 : String | Tuples.cs:141:22:141:28 | (..., ...) : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item1] : String | Tuples.cs:145:22:145:23 | access to local variable a1 | provenance | | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item1] : String | Tuples.cs:145:22:145:23 | access to local variable a1 | provenance | | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:144:27:144:42 | { ... } : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:144:27:144:42 | { ... } : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:144:27:144:42 | { ... } : ValueTuple [field Item2] : String | Tuples.cs:146:22:146:23 | access to local variable c1 | provenance | | +| Tuples.cs:144:27:144:42 | { ... } : ValueTuple [field Item2] : String | Tuples.cs:146:22:146:23 | access to local variable c1 | provenance | | +| Tuples.cs:151:13:151:14 | access to local variable o3 : String | Tuples.cs:153:18:153:19 | access to local variable o3 : String | provenance | | +| Tuples.cs:151:13:151:14 | access to local variable o3 : String | Tuples.cs:153:18:153:19 | access to local variable o3 : String | provenance | | +| Tuples.cs:151:18:151:35 | call to method Source : String | Tuples.cs:151:13:151:14 | access to local variable o3 : String | provenance | | +| Tuples.cs:151:18:151:35 | call to method Source : String | Tuples.cs:151:13:151:14 | access to local variable o3 : String | provenance | | +| Tuples.cs:152:13:152:14 | access to local variable o4 : String | Tuples.cs:153:26:153:27 | access to local variable o4 : String | provenance | | +| Tuples.cs:152:13:152:14 | access to local variable o4 : String | Tuples.cs:153:26:153:27 | access to local variable o4 : String | provenance | | +| Tuples.cs:152:18:152:35 | call to method Source : String | Tuples.cs:152:13:152:14 | access to local variable o4 : String | provenance | | +| Tuples.cs:152:18:152:35 | call to method Source : String | Tuples.cs:152:13:152:14 | access to local variable o4 : String | provenance | | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item1] : String | Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item1] : String | Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:153:18:153:19 | access to local variable o3 : String | Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:153:18:153:19 | access to local variable o3 : String | Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | provenance | | +| Tuples.cs:153:22:153:28 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:153:22:153:28 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | provenance | | +| Tuples.cs:153:26:153:27 | access to local variable o4 : String | Tuples.cs:153:22:153:28 | (..., ...) : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:153:26:153:27 | access to local variable o4 : String | Tuples.cs:153:22:153:28 | (..., ...) : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item1] : String | Tuples.cs:156:18:156:19 | access to local variable a2 | provenance | | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item1] : String | Tuples.cs:156:18:156:19 | access to local variable a2 | provenance | | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:154:27:154:38 | (..., ...) : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:154:27:154:38 | (..., ...) : ValueTuple [field Item2] : String | provenance | | +| Tuples.cs:154:27:154:38 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:157:18:157:19 | access to local variable c2 | provenance | | +| Tuples.cs:154:27:154:38 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:157:18:157:19 | access to local variable c2 | provenance | | nodes | Tuples.cs:7:13:7:14 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | | Tuples.cs:7:13:7:14 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | @@ -439,6 +495,70 @@ nodes | Tuples.cs:133:28:133:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Tuples.cs:134:14:134:15 | access to local variable y4 | semmle.label | access to local variable y4 | | Tuples.cs:134:14:134:15 | access to local variable y4 | semmle.label | access to local variable y4 | +| Tuples.cs:139:13:139:14 | access to local variable o1 : String | semmle.label | access to local variable o1 : String | +| Tuples.cs:139:13:139:14 | access to local variable o1 : String | semmle.label | access to local variable o1 : String | +| Tuples.cs:139:18:139:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:139:18:139:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:140:13:140:14 | access to local variable o2 : String | semmle.label | access to local variable o2 : String | +| Tuples.cs:140:13:140:14 | access to local variable o2 : String | semmle.label | access to local variable o2 : String | +| Tuples.cs:140:18:140:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:140:18:140:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item1] : String | semmle.label | access to local variable x : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item1] : String | semmle.label | access to local variable x : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:141:13:141:13 | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | access to local variable x : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:141:17:141:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:141:18:141:19 | access to local variable o1 : String | semmle.label | access to local variable o1 : String | +| Tuples.cs:141:18:141:19 | access to local variable o1 : String | semmle.label | access to local variable o1 : String | +| Tuples.cs:141:22:141:28 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:141:22:141:28 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:141:26:141:27 | access to local variable o2 : String | semmle.label | access to local variable o2 : String | +| Tuples.cs:141:26:141:27 | access to local variable o2 : String | semmle.label | access to local variable o2 : String | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item1] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item1] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:144:18:144:46 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:144:27:144:42 | { ... } : ValueTuple [field Item2] : String | semmle.label | { ... } : ValueTuple [field Item2] : String | +| Tuples.cs:144:27:144:42 | { ... } : ValueTuple [field Item2] : String | semmle.label | { ... } : ValueTuple [field Item2] : String | +| Tuples.cs:145:22:145:23 | access to local variable a1 | semmle.label | access to local variable a1 | +| Tuples.cs:145:22:145:23 | access to local variable a1 | semmle.label | access to local variable a1 | +| Tuples.cs:146:22:146:23 | access to local variable c1 | semmle.label | access to local variable c1 | +| Tuples.cs:146:22:146:23 | access to local variable c1 | semmle.label | access to local variable c1 | +| Tuples.cs:151:13:151:14 | access to local variable o3 : String | semmle.label | access to local variable o3 : String | +| Tuples.cs:151:13:151:14 | access to local variable o3 : String | semmle.label | access to local variable o3 : String | +| Tuples.cs:151:18:151:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:151:18:151:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:152:13:152:14 | access to local variable o4 : String | semmle.label | access to local variable o4 : String | +| Tuples.cs:152:13:152:14 | access to local variable o4 : String | semmle.label | access to local variable o4 : String | +| Tuples.cs:152:18:152:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:152:18:152:35 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item1] : String | semmle.label | access to local variable y : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item1] : String | semmle.label | access to local variable y : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:153:13:153:13 | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | access to local variable y : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:153:17:153:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:153:18:153:19 | access to local variable o3 : String | semmle.label | access to local variable o3 : String | +| Tuples.cs:153:18:153:19 | access to local variable o3 : String | semmle.label | access to local variable o3 : String | +| Tuples.cs:153:22:153:28 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:153:22:153:28 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:153:26:153:27 | access to local variable o4 : String | semmle.label | access to local variable o4 : String | +| Tuples.cs:153:26:153:27 | access to local variable o4 : String | semmle.label | access to local variable o4 : String | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item1] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item1] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:154:18:154:42 | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | { ... } : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:154:27:154:38 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:154:27:154:38 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:156:18:156:19 | access to local variable a2 | semmle.label | access to local variable a2 | +| Tuples.cs:156:18:156:19 | access to local variable a2 | semmle.label | access to local variable a2 | +| Tuples.cs:157:18:157:19 | access to local variable c2 | semmle.label | access to local variable c2 | +| Tuples.cs:157:18:157:19 | access to local variable c2 | semmle.label | access to local variable c2 | subpaths | Tuples.cs:100:24:100:24 | access to local variable o : String | Tuples.cs:95:22:95:22 | i : String | Tuples.cs:95:12:95:13 | this [Return] : R1 [property i] : String | Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | | Tuples.cs:100:24:100:24 | access to local variable o : String | Tuples.cs:95:22:95:22 | i : String | Tuples.cs:95:12:95:13 | this [Return] : R1 [property i] : String | Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | @@ -490,3 +610,11 @@ testFailures | Tuples.cs:130:14:130:15 | access to local variable y3 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | | Tuples.cs:134:14:134:15 | access to local variable y4 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | | Tuples.cs:134:14:134:15 | access to local variable y4 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:145:22:145:23 | access to local variable a1 | Tuples.cs:139:18:139:35 | call to method Source : String | Tuples.cs:145:22:145:23 | access to local variable a1 | $@ | Tuples.cs:139:18:139:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:145:22:145:23 | access to local variable a1 | Tuples.cs:139:18:139:35 | call to method Source : String | Tuples.cs:145:22:145:23 | access to local variable a1 | $@ | Tuples.cs:139:18:139:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:146:22:146:23 | access to local variable c1 | Tuples.cs:140:18:140:35 | call to method Source : String | Tuples.cs:146:22:146:23 | access to local variable c1 | $@ | Tuples.cs:140:18:140:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:146:22:146:23 | access to local variable c1 | Tuples.cs:140:18:140:35 | call to method Source : String | Tuples.cs:146:22:146:23 | access to local variable c1 | $@ | Tuples.cs:140:18:140:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:156:18:156:19 | access to local variable a2 | Tuples.cs:151:18:151:35 | call to method Source : String | Tuples.cs:156:18:156:19 | access to local variable a2 | $@ | Tuples.cs:151:18:151:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:156:18:156:19 | access to local variable a2 | Tuples.cs:151:18:151:35 | call to method Source : String | Tuples.cs:156:18:156:19 | access to local variable a2 | $@ | Tuples.cs:151:18:151:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:157:18:157:19 | access to local variable c2 | Tuples.cs:152:18:152:35 | call to method Source : String | Tuples.cs:157:18:157:19 | access to local variable c2 | $@ | Tuples.cs:152:18:152:35 | call to method Source : String | call to method Source : String | +| Tuples.cs:157:18:157:19 | access to local variable c2 | Tuples.cs:152:18:152:35 | call to method Source : String | Tuples.cs:157:18:157:19 | access to local variable c2 | $@ | Tuples.cs:152:18:152:35 | call to method Source : String | call to method Source : String |