Skip to content

Commit ff369f2

Browse files
authored
Merge pull request #7846 from michaelnebel/csharp/deconstruction
C# 10: Tuple deconstruction.
2 parents bbbb526 + f21e084 commit ff369f2

File tree

9 files changed

+1238
-664
lines changed

9 files changed

+1238
-664
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
3+
public class Deconstruction
4+
{
5+
public void M1()
6+
{
7+
// Declaration and Assignment
8+
(int x1, int y1) = (10, 11);
9+
10+
// Assignment
11+
int x2 = 0;
12+
int y2 = 0;
13+
(x2, y2) = (20, 21);
14+
15+
// Mixed
16+
int y3 = 0;
17+
(int x3, y3) = (30, 31);
18+
19+
int x4 = 0;
20+
(x4, int y4) = (40, 41);
21+
22+
// Nested, Mixed
23+
int x5 = 0;
24+
int y51 = 0;
25+
(x5, (int y50, y51)) = (50, (51, 52));
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
declarations
2+
| Tuples.cs:8:14:8:15 | Int32 x1 |
3+
| Tuples.cs:8:22:8:23 | Int32 y1 |
4+
| Tuples.cs:17:14:17:15 | Int32 x3 |
5+
| Tuples.cs:20:18:20:19 | Int32 y4 |
6+
| Tuples.cs:25:19:25:21 | Int32 y50 |
7+
assignments
8+
| Tuples.cs:8:9:8:35 | ... = ... | Tuples.cs:8:14:8:15 | x1 | 0 |
9+
| Tuples.cs:8:9:8:35 | ... = ... | Tuples.cs:8:22:8:23 | y1 | 1 |
10+
| Tuples.cs:13:9:13:27 | ... = ... | Tuples.cs:11:13:11:14 | x2 | 0 |
11+
| Tuples.cs:13:9:13:27 | ... = ... | Tuples.cs:12:13:12:14 | y2 | 1 |
12+
| Tuples.cs:17:9:17:31 | ... = ... | Tuples.cs:16:13:16:14 | y3 | 1 |
13+
| Tuples.cs:17:9:17:31 | ... = ... | Tuples.cs:17:14:17:15 | x3 | 0 |
14+
| Tuples.cs:20:9:20:31 | ... = ... | Tuples.cs:19:13:19:14 | x4 | 0 |
15+
| Tuples.cs:20:9:20:31 | ... = ... | Tuples.cs:20:18:20:19 | y4 | 1 |
16+
| Tuples.cs:25:9:25:45 | ... = ... | Tuples.cs:23:13:23:14 | x5 | 0 |
17+
| Tuples.cs:25:9:25:45 | ... = ... | Tuples.cs:24:13:24:15 | y51 | 2 |
18+
| Tuples.cs:25:9:25:45 | ... = ... | Tuples.cs:25:19:25:21 | y50 | 1 |
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import csharp
2+
3+
private predicate relevant(Element e) { e.getFile().getBaseName() = "Tuples.cs" }
4+
5+
query predicate declarations(LocalVariableDeclExpr d) {
6+
relevant(d) and
7+
d.getParent*() instanceof TupleExpr
8+
}
9+
10+
query predicate assignments(AssignableDefinitions::TupleAssignmentDefinition t, Assignable a, int o) {
11+
relevant(t.getAssignment()) and
12+
a = t.getTarget() and
13+
o = t.getEvaluationOrder()
14+
}

csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public record class RecordClass2(object Prop) { }
44

55
public record class Nested(RecordClass2 Record) { }
66

7-
public class K
7+
public class RecordPatterns
88
{
99
private void M1()
1010
{

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

Lines changed: 172 additions & 111 deletions
Large diffs are not rendered by default.

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

Lines changed: 502 additions & 339 deletions
Large diffs are not rendered by default.

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

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,80 +4,90 @@ class Tuples
44
{
55
static void M1()
66
{
7-
var x = (a: "taint source", (1, "taint source"));
7+
var o1 = Source<object>(1);
8+
var o2 = Source<object>(2);
9+
10+
var x = (a: o1, (1, o2));
811
var (a, (b, c)) = x;
9-
Sink(a); // Tainted
12+
Sink(a); // $ hasValueFlow=1
1013
Sink(b);
11-
Sink(c); // Tainted
14+
Sink(c); // $ hasValueFlow=2
1215

1316
(a, (b, c)) = x;
14-
Sink(a); // Tainted
17+
Sink(a); // $ hasValueFlow=1
1518
Sink(b);
16-
Sink(c); // Tainted
19+
Sink(c); // $ hasValueFlow=2
1720

1821
(var p, var q) = x;
19-
Sink(p); // Tainted
22+
Sink(p); // $ hasValueFlow=1
2023
Sink(q.Item1);
21-
Sink(q.Item2); // Tainted
24+
Sink(q.Item2); // $ hasValueFlow=2
2225

23-
Sink(x.Item1); // Tainted
24-
Sink(x.a); // Tainted
26+
Sink(x.Item1); // $ hasValueFlow=1
27+
Sink(x.a); // $ hasValueFlow=1
2528
Sink(x.Item2.Item1);
26-
Sink(x.Item2.Item2); // Tainted
29+
Sink(x.Item2.Item2); // $ hasValueFlow=2
2730
}
2831

2932
static void M2()
3033
{
31-
var x = ("taint source", 2, 3, 4, 5, 6, 7, 8, 9, "taint source");
32-
Sink(x.Item1); // Tainted
34+
var o1 = Source<object>(3);
35+
var o2 = Source<object>(4);
36+
37+
var x = (o1, 2, 3, 4, 5, 6, 7, 8, 9, o2);
38+
Sink(x.Item1); // $ hasValueFlow=3
3339
Sink(x.Item2);
34-
Sink(x.Item10); // Tainted
40+
Sink(x.Item10); // $ hasValueFlow=4
3541
}
3642

3743
static void M3()
3844
{
39-
var x = (ValueTuple<string, int, int>)("taint source", 2, 3);
40-
Sink(x.Item1); // Tainted
45+
var o = Source<string>(5);
46+
var x = (ValueTuple<string, int, int>)(o, 2, 3);
47+
Sink(x.Item1); // $ hasValueFlow=5
4148
Sink(x.Item2);
4249

43-
var y = (ValueTuple<object, int, int>)("taint source", 2, 3);
44-
Sink(y.Item1); // Tainted, not found
50+
var y = (ValueTuple<object, int, int>)(o, 2, 3);
51+
Sink(y.Item1); // $ MISSING: hasValueFlow=5
4552
Sink(y.Item2);
4653
}
4754

4855
static void M4(string s)
4956
{
50-
var x = ("taint source", (2, "taint source"), 3);
57+
var o1 = Source<string>(6);
58+
var o2 = Source<string>(7);
59+
var x = (o1, (2, o2), 3);
5160
switch (x)
5261
{
5362
case ValueTuple<string, (int, string), int> t when t.Item3 > 1:
54-
Sink(t.Item1); // Tainted
55-
Sink(t.Item2.Item2); // Tainted
63+
Sink(t.Item1); // $ hasValueFlow=6
64+
Sink(t.Item2.Item2); // $ hasValueFlow=7
5665
Sink(t.Item2.Item1);
5766
break;
5867
case var (a, (b, c), _):
59-
Sink(a); // Tainted
60-
Sink(c); // Tainted
68+
Sink(a); // $ hasValueFlow=6
69+
Sink(c); // $ hasValueFlow=7
6170
Sink(b);
6271
break;
6372
}
6473

74+
var o3 = Source<string>(8);
6575
var y = (s, (2, s), 3);
6676
switch (y)
6777
{
68-
case ("taint source", var (b, c), _):
69-
Sink(y.Item1); // Tainted, not found
70-
Sink(y.Item2.Item2); // Tainted, not found
71-
Sink(c); // Tainted, not found
78+
case (var a, var (b, c), _) when a == o3:
79+
Sink(y.Item1); // $ MISSING: hasValueFlow=8
80+
Sink(y.Item2.Item2); // $ MISSING: hasValueFlow=8
81+
Sink(c); // $ MISSING: hasValueFlow=8
7282
Sink(y.Item2.Item1);
7383
Sink(b);
7484
break;
7585
}
7686

7787
if (x is var (p, (q, r), _))
7888
{
79-
Sink(p); // Tainted
80-
Sink(r); // Tainted
89+
Sink(p); // $ hasValueFlow=6
90+
Sink(r); // $ hasValueFlow=7
8191
Sink(q);
8292
}
8393
}
@@ -86,23 +96,47 @@ record R1(string i, int j) { };
8696

8797
static void M5()
8898
{
89-
var r = new R1("taint source", 1);
90-
Sink(r.i); // Tainted
99+
var o = Source<string>(9);
100+
var r = new R1(o, 1);
101+
Sink(r.i); // $ hasValueFlow=9
91102

92103
var (a, b) = r;
93-
Sink(a); // Tainted, not found
104+
Sink(a); // $ MISSING: hasValueFlow=9
94105
Sink(b);
95106

96107
switch (r)
97108
{
98109
case var (x, y):
99-
Sink(x); // Tainted, not found
110+
Sink(x); // $ MISSING: hasValueFlow=9
100111
Sink(y);
101112
break;
102113
}
103114
}
104115

105-
static void Sink<T>(T x) { }
116+
static void M6()
117+
{
118+
var o = Source<object>(9);
119+
120+
int y1 = 0;
121+
(object x1, y1) = (o, 1);
122+
Sink(x1); // $ hasValueFlow=9
123+
124+
var x2 = new object();
125+
(x2, int y2) = (o, 1);
126+
Sink(x2); // $ hasValueFlow=9
127+
128+
var x3 = 0;
129+
(x3, object y3) = (1, o);
130+
Sink(y3); // $ hasValueFlow=9
131+
132+
var y4 = new object();
133+
(int x4, y4) = (1, o);
134+
Sink(y4); // $ hasValueFlow=9
135+
}
136+
137+
public static void Sink(object o) { }
138+
139+
static T Source<T>(object source) => throw null;
106140
}
107141

108142
namespace System.Runtime.CompilerServices

0 commit comments

Comments
 (0)