Skip to content

Commit f072e41

Browse files
authored
Merge pull request #15652 from michaelnebel/csharp/constructorflow
C#: Read-only property flow.
2 parents 70a2d16 + 060133d commit f072e41

File tree

5 files changed

+84
-5
lines changed

5 files changed

+84
-5
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* C#: Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.

csharp/ql/lib/semmle/code/csharp/Property.qll

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
127127
properties(this, _, _, getTypeRef(result), _)
128128
}
129129

130+
private predicate isAutoPartial() {
131+
this.fromSource() and
132+
not this.isExtern() and
133+
not this.isAbstract() and
134+
not this.getAnAccessor().hasBody()
135+
}
136+
130137
/**
131138
* Holds if this property is automatically implemented. For example, `P1`
132139
* on line 2 is automatically implemented, while `P2` on line 5 is not in
@@ -147,11 +154,22 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
147154
* code.
148155
*/
149156
predicate isAutoImplemented() {
150-
this.fromSource() and
151-
this.isReadWrite() and
152-
not this.isExtern() and
153-
not this.isAbstract() and
154-
not this.getAnAccessor().hasBody()
157+
this.isAutoPartial() and
158+
this.isReadWrite()
159+
}
160+
161+
/**
162+
* Holds if this property is automatically implemented and read-only. For
163+
* example, `P1` on line 2 is automatically implemented and read-only
164+
* ```csharp
165+
* class C {
166+
* public int P1 { get; }
167+
* }
168+
* ```
169+
*/
170+
predicate isAutoImplementedReadOnly() {
171+
this.isAutoPartial() and
172+
this.isReadOnly()
155173
}
156174

157175
override Property getUnboundDeclaration() { properties(this, _, _, _, result) }

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,8 @@ class FieldOrProperty extends Assignable, Modifiable {
18991899
(
19001900
p.isAutoImplemented()
19011901
or
1902+
p.isAutoImplementedReadOnly()
1903+
or
19021904
p.matchesHandle(any(CIL::TrivialProperty tp))
19031905
or
19041906
p.getDeclaringType() instanceof AnonymousClass

csharp/ql/test/library-tests/dataflow/constructors/ConstructorFlow.expected

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@ edges
6464
| Constructors.cs:112:25:112:27 | access to local variable o31 : Object | Constructors.cs:112:18:112:28 | object creation of type C3 : C3 [parameter o31param] : Object | provenance | |
6565
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | Constructors.cs:106:32:106:39 | this : C3 [parameter o31param] : Object | provenance | |
6666
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | Constructors.cs:113:14:113:21 | access to property Obj31 | provenance | |
67+
| Constructors.cs:121:26:121:28 | oc1 : Object | Constructors.cs:123:20:123:22 | access to parameter oc1 : Object | provenance | |
68+
| Constructors.cs:121:38:121:40 | oc2 : Object | Constructors.cs:124:20:124:22 | access to parameter oc2 : Object | provenance | |
69+
| Constructors.cs:123:20:123:22 | access to parameter oc1 : Object | Constructors.cs:123:13:123:16 | [post] this access : C4 [property Obj1] : Object | provenance | |
70+
| Constructors.cs:124:20:124:22 | access to parameter oc2 : Object | Constructors.cs:124:13:124:16 | [post] this access : C4 [property Obj2] : Object | provenance | |
71+
| Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | Constructors.cs:132:25:132:26 | access to local variable o1 : Object | provenance | |
72+
| Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | Constructors.cs:132:29:132:30 | access to local variable o2 : Object | provenance | |
73+
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object | Constructors.cs:133:14:133:15 | access to local variable c4 : C4 [property Obj1] : Object | provenance | |
74+
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object | Constructors.cs:134:14:134:15 | access to local variable c4 : C4 [property Obj2] : Object | provenance | |
75+
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | Constructors.cs:121:26:121:28 | oc1 : Object | provenance | |
76+
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object | provenance | |
77+
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:121:38:121:40 | oc2 : Object | provenance | |
78+
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object | provenance | |
79+
| Constructors.cs:133:14:133:15 | access to local variable c4 : C4 [property Obj1] : Object | Constructors.cs:133:14:133:20 | access to property Obj1 | provenance | |
80+
| Constructors.cs:134:14:134:15 | access to local variable c4 : C4 [property Obj2] : Object | Constructors.cs:134:14:134:20 | access to property Obj2 | provenance | |
6781
nodes
6882
| Constructors.cs:5:24:5:25 | [post] this access : C_no_ctor [field s1] : Object | semmle.label | [post] this access : C_no_ctor [field s1] : Object |
6983
| Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
@@ -134,6 +148,22 @@ nodes
134148
| Constructors.cs:112:25:112:27 | access to local variable o31 : Object | semmle.label | access to local variable o31 : Object |
135149
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | semmle.label | access to local variable c3 : C3 [parameter o31param] : Object |
136150
| Constructors.cs:113:14:113:21 | access to property Obj31 | semmle.label | access to property Obj31 |
151+
| Constructors.cs:121:26:121:28 | oc1 : Object | semmle.label | oc1 : Object |
152+
| Constructors.cs:121:38:121:40 | oc2 : Object | semmle.label | oc2 : Object |
153+
| Constructors.cs:123:13:123:16 | [post] this access : C4 [property Obj1] : Object | semmle.label | [post] this access : C4 [property Obj1] : Object |
154+
| Constructors.cs:123:20:123:22 | access to parameter oc1 : Object | semmle.label | access to parameter oc1 : Object |
155+
| Constructors.cs:124:13:124:16 | [post] this access : C4 [property Obj2] : Object | semmle.label | [post] this access : C4 [property Obj2] : Object |
156+
| Constructors.cs:124:20:124:22 | access to parameter oc2 : Object | semmle.label | access to parameter oc2 : Object |
157+
| Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
158+
| Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
159+
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object | semmle.label | object creation of type C4 : C4 [property Obj1] : Object |
160+
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object | semmle.label | object creation of type C4 : C4 [property Obj2] : Object |
161+
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object |
162+
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object |
163+
| Constructors.cs:133:14:133:15 | access to local variable c4 : C4 [property Obj1] : Object | semmle.label | access to local variable c4 : C4 [property Obj1] : Object |
164+
| Constructors.cs:133:14:133:20 | access to property Obj1 | semmle.label | access to property Obj1 |
165+
| Constructors.cs:134:14:134:15 | access to local variable c4 : C4 [property Obj2] : Object | semmle.label | access to local variable c4 : C4 [property Obj2] : Object |
166+
| Constructors.cs:134:14:134:20 | access to property Obj2 | semmle.label | access to property Obj2 |
137167
subpaths
138168
| Constructors.cs:64:37:64:37 | access to parameter o : Object | Constructors.cs:57:54:57:55 | o2 : Object | Constructors.cs:59:13:59:19 | SSA def(o1) : Object | Constructors.cs:64:27:64:34 | SSA def(o22param) : Object |
139169
| Constructors.cs:71:25:71:25 | access to local variable o : Object | Constructors.cs:41:26:41:26 | o : Object | Constructors.cs:41:32:41:34 | [post] this access : C1 [field Obj] : Object | Constructors.cs:71:18:71:26 | object creation of type C1 : C1 [field Obj] : Object |
@@ -147,6 +177,8 @@ subpaths
147177
| Constructors.cs:101:14:101:15 | access to local variable c2 : C2 [parameter o22param] : Object | Constructors.cs:48:32:48:39 | this : C2 [parameter o22param] : Object | Constructors.cs:48:32:48:39 | access to parameter o22param : Object | Constructors.cs:101:14:101:21 | access to property Obj22 |
148178
| Constructors.cs:112:25:112:27 | access to local variable o31 : Object | Constructors.cs:104:28:104:35 | o31param : Object | Constructors.cs:104:28:104:35 | o31param : Object | Constructors.cs:112:18:112:28 | object creation of type C3 : C3 [parameter o31param] : Object |
149179
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | Constructors.cs:106:32:106:39 | this : C3 [parameter o31param] : Object | Constructors.cs:106:32:106:39 | access to parameter o31param : Object | Constructors.cs:113:14:113:21 | access to property Obj31 |
180+
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | Constructors.cs:121:26:121:28 | oc1 : Object | Constructors.cs:123:13:123:16 | [post] this access : C4 [property Obj1] : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object |
181+
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:121:38:121:40 | oc2 : Object | Constructors.cs:124:13:124:16 | [post] this access : C4 [property Obj2] : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object |
150182
#select
151183
| Constructors.cs:15:18:15:19 | access to field s1 | Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | Constructors.cs:15:18:15:19 | access to field s1 | $@ | Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | call to method Source<Object> : Object |
152184
| Constructors.cs:33:18:33:19 | access to field s1 | Constructors.cs:21:29:21:45 | call to method Source<Object> : Object | Constructors.cs:33:18:33:19 | access to field s1 | $@ | Constructors.cs:21:29:21:45 | call to method Source<Object> : Object | call to method Source<Object> : Object |
@@ -157,3 +189,5 @@ subpaths
157189
| Constructors.cs:93:14:93:21 | access to property Obj22 | Constructors.cs:91:21:91:37 | call to method Source<Object> : Object | Constructors.cs:93:14:93:21 | access to property Obj22 | $@ | Constructors.cs:91:21:91:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
158190
| Constructors.cs:101:14:101:21 | access to property Obj22 | Constructors.cs:99:21:99:37 | call to method Source<Object> : Object | Constructors.cs:101:14:101:21 | access to property Obj22 | $@ | Constructors.cs:99:21:99:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
159191
| Constructors.cs:113:14:113:21 | access to property Obj31 | Constructors.cs:111:19:111:35 | call to method Source<Object> : Object | Constructors.cs:113:14:113:21 | access to property Obj31 | $@ | Constructors.cs:111:19:111:35 | call to method Source<Object> : Object | call to method Source<Object> : Object |
192+
| Constructors.cs:133:14:133:20 | access to property Obj1 | Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | Constructors.cs:133:14:133:20 | access to property Obj1 | $@ | Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
193+
| Constructors.cs:134:14:134:20 | access to property Obj2 | Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | Constructors.cs:134:14:134:20 | access to property Obj2 | $@ | Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |

csharp/ql/test/library-tests/dataflow/constructors/Constructors.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,27 @@ public void M5()
113113
Sink(c3.Obj31); // $ hasValueFlow=6
114114
}
115115

116+
public class C4
117+
{
118+
public object Obj1 { get; init; }
119+
public object Obj2 { get; }
120+
121+
public C4(object oc1, object oc2)
122+
{
123+
Obj1 = oc1;
124+
Obj2 = oc2;
125+
}
126+
}
127+
128+
public void M6()
129+
{
130+
var o1 = Source<object>(7);
131+
var o2 = Source<object>(8);
132+
var c4 = new C4(o1, o2);
133+
Sink(c4.Obj1); // $ hasValueFlow=7
134+
Sink(c4.Obj2); // $ hasValueFlow=8
135+
}
136+
116137
public static void Sink(object o) { }
117138

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

0 commit comments

Comments
 (0)