Skip to content

Commit 9d89cac

Browse files
authored
Merge pull request github#7643 from michaelnebel/csharp/struct-improvements
C#: Struct (and to a minor extent anonymous types) improvements
2 parents 1eaa379 + e804922 commit 9d89cac

File tree

12 files changed

+450
-75
lines changed

12 files changed

+450
-75
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,8 @@ class FieldOrProperty extends Assignable, Modifiable {
14811481
p.isAutoImplemented()
14821482
or
14831483
p.matchesHandle(any(CIL::TrivialProperty tp))
1484+
or
1485+
p.getDeclaringType() instanceof AnonymousClass
14841486
)
14851487
)
14861488
}

csharp/ql/test/library-tests/csharp10/RecordTypes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ public record class MyClassRecord(DateTime stuff) { }
99

1010
public readonly record struct MyReadonlyRecordStruct(string Stuff) { }
1111

12-
public record struct MyRecordStruct(int Stuff) { }
12+
public record struct MyRecordStruct1(int Stuff) { }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
// Struct with user declared parameterless constructor.
4+
public struct MyStructParameterlessConstructor
5+
{
6+
public int X;
7+
public readonly int Y;
8+
public int Z { get; }
9+
10+
public MyStructParameterlessConstructor()
11+
{
12+
X = 1;
13+
Y = 2;
14+
Z = 3;
15+
}
16+
}
17+
18+
// Struct with compiler generated parameterless constructor.
19+
public struct MyDefaultStruct { }
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
3+
public struct MyStruct
4+
{
5+
public int X;
6+
public MyStruct(int x) => X = x;
7+
}
8+
9+
public record struct MyRecordStruct2(int Y) { }
10+
11+
public class MyWithExamples
12+
{
13+
public void M1()
14+
{
15+
var s1 = new MyStruct(1);
16+
var s2 = s1 with { X = 2 };
17+
}
18+
19+
public void M2()
20+
{
21+
var r1 = new MyRecordStruct2(4);
22+
var r2 = r1 with { Y = 6 };
23+
}
24+
25+
public void M3()
26+
{
27+
var anon1 = new { A = 3, B = 4 };
28+
var anon2 = anon1 with { A = 5 };
29+
}
30+
}

csharp/ql/test/library-tests/csharp10/recordTypes.expected

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ recordTypes
22
| RecordTypes.cs:3:1:6:2 | MyEntry |
33
| RecordTypes.cs:8:1:8:53 | MyClassRecord |
44
| RecordTypes.cs:10:1:10:70 | MyReadonlyRecordStruct |
5-
| RecordTypes.cs:12:1:12:50 | MyRecordStruct |
5+
| RecordTypes.cs:12:1:12:51 | MyRecordStruct1 |
6+
| WithExpression.cs:9:1:9:47 | MyRecordStruct2 |
67
recordStructs
78
| RecordTypes.cs:10:1:10:70 | MyReadonlyRecordStruct |
8-
| RecordTypes.cs:12:1:12:50 | MyRecordStruct |
9+
| RecordTypes.cs:12:1:12:51 | MyRecordStruct1 |
10+
| WithExpression.cs:9:1:9:47 | MyRecordStruct2 |
911
recordClass
1012
| RecordTypes.cs:3:1:6:2 | MyEntry |
1113
| RecordTypes.cs:8:1:8:53 | MyClassRecord |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
structAllDefaultConstructors
2+
| StructTypes.cs:4:15:4:46 | MyStructParameterlessConstructor | StructTypes.cs:10:12:10:43 | MyStructParameterlessConstructor |
3+
| StructTypes.cs:19:15:19:29 | MyDefaultStruct | StructTypes.cs:19:15:19:29 | MyDefaultStruct |
4+
structFromSourceDefaultConstructors
5+
| StructTypes.cs:4:15:4:46 | MyStructParameterlessConstructor | StructTypes.cs:10:12:10:43 | MyStructParameterlessConstructor |
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import csharp
2+
3+
predicate structDefaultConstructors(Struct struct, Constructor c) {
4+
struct.getAConstructor() = c and
5+
struct.getFile().getBaseName() = "StructTypes.cs" and
6+
c.hasNoParameters()
7+
}
8+
9+
query predicate structAllDefaultConstructors(Struct struct, Constructor c) {
10+
structDefaultConstructors(struct, c)
11+
}
12+
13+
query predicate structFromSourceDefaultConstructors(Struct struct, Constructor c) {
14+
structDefaultConstructors(struct, c) and c.fromSource()
15+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| WithExpression.cs:16:18:16:34 | ... with { ... } | MyStruct | WithExpression.cs:16:18:16:19 | access to local variable s1 | WithExpression.cs:16:26:16:34 | { ..., ... } |
2+
| WithExpression.cs:22:18:22:34 | ... with { ... } | MyRecordStruct2 | WithExpression.cs:22:18:22:19 | access to local variable r1 | WithExpression.cs:22:26:22:34 | { ..., ... } |
3+
| WithExpression.cs:28:21:28:40 | ... with { ... } | <>__AnonType0<Int32,Int32> | WithExpression.cs:28:21:28:25 | access to local variable anon1 | WithExpression.cs:28:32:28:40 | { ..., ... } |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import csharp
2+
3+
query predicate withExpressions(WithExpr with, string type, Expr expr, ObjectInitializer init) {
4+
type = with.getType().toStringWithTypes() and
5+
expr = with.getExpr() and
6+
init = with.getInitializer()
7+
}

csharp/ql/test/library-tests/dataflow/fields/F.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ public class F
55

66
static F Create(object o1, object o2) => new F() { Field1 = o1, Field2 = o2 };
77

8-
private void M()
8+
private void M1()
99
{
1010
var o = Source<object>(1);
1111
var f = Create(o, null);
@@ -25,6 +25,15 @@ private void M()
2525
Sink(f.Field2); // $ hasValueFlow=4
2626
}
2727

28+
private void M2()
29+
{
30+
var o = Source<object>(2);
31+
object @null = null;
32+
var a = new { X = o, Y = @null };
33+
Sink(a.X); // $ hasValueFlow=2
34+
Sink(a.Y); // no flow
35+
}
36+
2837
public static void Sink(object o) { }
2938

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

0 commit comments

Comments
 (0)