Skip to content

Commit 7ce7b58

Browse files
authored
Merge pull request github#15657 from michaelnebel/csharp/recordflow
C#: Use primary constructors for record types for dataflow.
2 parents 95ce0cd + f2c849c commit 7ce7b58

File tree

6 files changed

+58
-58
lines changed

6 files changed

+58
-58
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,9 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
20742074
exists(Parameter p |
20752075
node1 = TExplicitParameterNode(p) and
20762076
node2 = TPrimaryConstructorThisAccessNode(p, true) and
2077-
c.(PrimaryConstructorParameterContent).getParameter() = p
2077+
if p.getCallable().getDeclaringType() instanceof RecordType
2078+
then c.(PropertyContent).getProperty().getName() = p.getName()
2079+
else c.(PrimaryConstructorParameterContent).getParameter() = p
20782080
)
20792081
or
20802082
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,

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

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -358,63 +358,6 @@ private module BidirectionalImports {
358358
private import semmle.code.csharp.frameworks.EntityFramework
359359
}
360360

361-
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
362-
c = any(RecordType r).getAMember() and
363-
exists(string name |
364-
c.getParameter(i).getName() = name and
365-
c.getDeclaringType().getAMember(name) = p
366-
)
367-
}
368-
369-
private class RecordConstructorFlow extends Impl::Private::SummarizedCallableImpl {
370-
RecordConstructorFlow() { recordConstructorFlow(this, _, _) }
371-
372-
predicate propagatesFlowImpl(
373-
Impl::Private::SummaryComponentStack input, Impl::Private::SummaryComponentStack output,
374-
boolean preservesValue
375-
) {
376-
exists(int i, Property p |
377-
recordConstructorFlow(this, i, p) and
378-
input = Private::SummaryComponentStack::argument(i) and
379-
output =
380-
Private::SummaryComponentStack::propertyOf(p, Private::SummaryComponentStack::return()) and
381-
preservesValue = true
382-
)
383-
}
384-
385-
override predicate propagatesFlow(
386-
Impl::Private::SummaryComponentStack input, Impl::Private::SummaryComponentStack output,
387-
boolean preservesValue
388-
) {
389-
this.propagatesFlowImpl(input, output, preservesValue)
390-
}
391-
392-
override predicate hasProvenance(Public::Provenance provenance) { provenance = "manual" }
393-
}
394-
395-
// see `SummarizedCallableImpl` qldoc
396-
private class RecordConstructorFlowAdapter extends Impl::Public::SummarizedCallable instanceof RecordConstructorFlow
397-
{
398-
override predicate propagatesFlow(string input, string output, boolean preservesValue) { none() }
399-
400-
override predicate hasProvenance(Public::Provenance provenance) {
401-
RecordConstructorFlow.super.hasProvenance(provenance)
402-
}
403-
}
404-
405-
private class RecordConstructorFlowRequiredSummaryComponentStack extends Impl::Private::RequiredSummaryComponentStack
406-
{
407-
override predicate required(
408-
Impl::Private::SummaryComponent head, Impl::Private::SummaryComponentStack tail
409-
) {
410-
exists(Property p |
411-
recordConstructorFlow(_, _, p) and
412-
head = Private::SummaryComponent::property(p) and
413-
tail = Private::SummaryComponentStack::return()
414-
)
415-
}
416-
}
417-
418361
private import semmle.code.csharp.frameworks.system.linq.Expressions
419362

420363
private predicate mayInvokeCallback(Callable c, int n) {

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ edges
7878
| 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 | |
7979
| 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 | |
8080
| 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 | |
81+
| Constructors.cs:141:18:141:34 | call to method Source<Object> : Object | Constructors.cs:143:25:143:26 | access to local variable o1 : Object | provenance | |
82+
| Constructors.cs:142:18:142:35 | call to method Source<Object> : Object | Constructors.cs:143:29:143:30 | access to local variable o2 : Object | provenance | |
83+
| Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj1] : Object | Constructors.cs:144:14:144:15 | access to local variable r1 : R1 [property Obj1] : Object | provenance | |
84+
| Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj2] : Object | Constructors.cs:145:14:145:15 | access to local variable r1 : R1 [property Obj2] : Object | provenance | |
85+
| Constructors.cs:143:25:143:26 | access to local variable o1 : Object | Constructors.cs:137:29:137:32 | Obj1 : Object | provenance | |
86+
| Constructors.cs:143:25:143:26 | access to local variable o1 : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj1] : Object | provenance | |
87+
| Constructors.cs:143:29:143:30 | access to local variable o2 : Object | Constructors.cs:137:42:137:45 | Obj2 : Object | provenance | |
88+
| Constructors.cs:143:29:143:30 | access to local variable o2 : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj2] : Object | provenance | |
89+
| Constructors.cs:144:14:144:15 | access to local variable r1 : R1 [property Obj1] : Object | Constructors.cs:144:14:144:20 | access to property Obj1 | provenance | |
90+
| Constructors.cs:145:14:145:15 | access to local variable r1 : R1 [property Obj2] : Object | Constructors.cs:145:14:145:20 | access to property Obj2 | provenance | |
8191
nodes
8292
| 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 |
8393
| Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
@@ -164,6 +174,18 @@ nodes
164174
| Constructors.cs:133:14:133:20 | access to property Obj1 | semmle.label | access to property Obj1 |
165175
| 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 |
166176
| Constructors.cs:134:14:134:20 | access to property Obj2 | semmle.label | access to property Obj2 |
177+
| Constructors.cs:137:29:137:32 | Obj1 : Object | semmle.label | Obj1 : Object |
178+
| Constructors.cs:137:42:137:45 | Obj2 : Object | semmle.label | Obj2 : Object |
179+
| Constructors.cs:141:18:141:34 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
180+
| Constructors.cs:142:18:142:35 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
181+
| Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj1] : Object | semmle.label | object creation of type R1 : R1 [property Obj1] : Object |
182+
| Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj2] : Object | semmle.label | object creation of type R1 : R1 [property Obj2] : Object |
183+
| Constructors.cs:143:25:143:26 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object |
184+
| Constructors.cs:143:29:143:30 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object |
185+
| Constructors.cs:144:14:144:15 | access to local variable r1 : R1 [property Obj1] : Object | semmle.label | access to local variable r1 : R1 [property Obj1] : Object |
186+
| Constructors.cs:144:14:144:20 | access to property Obj1 | semmle.label | access to property Obj1 |
187+
| Constructors.cs:145:14:145:15 | access to local variable r1 : R1 [property Obj2] : Object | semmle.label | access to local variable r1 : R1 [property Obj2] : Object |
188+
| Constructors.cs:145:14:145:20 | access to property Obj2 | semmle.label | access to property Obj2 |
167189
subpaths
168190
| 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 |
169191
| 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 |
@@ -179,6 +201,8 @@ subpaths
179201
| 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 |
180202
| 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 |
181203
| 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 |
204+
| Constructors.cs:143:25:143:26 | access to local variable o1 : Object | Constructors.cs:137:29:137:32 | Obj1 : Object | Constructors.cs:137:29:137:32 | Obj1 : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj1] : Object |
205+
| Constructors.cs:143:29:143:30 | access to local variable o2 : Object | Constructors.cs:137:42:137:45 | Obj2 : Object | Constructors.cs:137:42:137:45 | Obj2 : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj2] : Object |
182206
#select
183207
| 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 |
184208
| 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 |
@@ -191,3 +215,5 @@ subpaths
191215
| 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 |
192216
| 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 |
193217
| 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 |
218+
| Constructors.cs:144:14:144:20 | access to property Obj1 | Constructors.cs:141:18:141:34 | call to method Source<Object> : Object | Constructors.cs:144:14:144:20 | access to property Obj1 | $@ | Constructors.cs:141:18:141:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
219+
| Constructors.cs:145:14:145:20 | access to property Obj2 | Constructors.cs:142:18:142:35 | call to method Source<Object> : Object | Constructors.cs:145:14:145:20 | access to property Obj2 | $@ | Constructors.cs:142:18:142:35 | call to method Source<Object> : Object | call to method Source<Object> : Object |

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ public void M6()
134134
Sink(c4.Obj2); // $ hasValueFlow=8
135135
}
136136

137+
public record R1(object Obj1, object Obj2);
138+
139+
public void M7()
140+
{
141+
var o1 = Source<object>(9);
142+
var o2 = Source<object>(10);
143+
var r1 = new R1(o1, o2);
144+
Sink(r1.Obj1); // $ hasValueFlow=9
145+
Sink(r1.Obj2); // $ hasValueFlow=10
146+
}
147+
137148
public static void Sink(object o) { }
138149

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

csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ edges
814814
| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | provenance | |
815815
| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | provenance | |
816816
| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | provenance | |
817+
| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:6:40:6:44 | Prop1 : Object | provenance | |
818+
| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:6:40:6:44 | Prop1 : Object | provenance | |
817819
| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | provenance | |
818820
| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | provenance | |
819821
| J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | J.cs:23:14:23:21 | access to property Prop1 | provenance | |
@@ -836,6 +838,8 @@ edges
836838
| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | provenance | |
837839
| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | provenance | |
838840
| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | provenance | |
841+
| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:8:42:8:46 | Prop1 : Object | provenance | |
842+
| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:8:42:8:46 | Prop1 : Object | provenance | |
839843
| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | provenance | |
840844
| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | provenance | |
841845
| J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | J.cs:43:14:43:21 | access to property Prop1 | provenance | |
@@ -1781,6 +1785,10 @@ nodes
17811785
| I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | semmle.label | access to parameter i : I [field Field1] : Object |
17821786
| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 |
17831787
| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 |
1788+
| J.cs:6:40:6:44 | Prop1 : Object | semmle.label | Prop1 : Object |
1789+
| J.cs:6:40:6:44 | Prop1 : Object | semmle.label | Prop1 : Object |
1790+
| J.cs:8:42:8:46 | Prop1 : Object | semmle.label | Prop1 : Object |
1791+
| J.cs:8:42:8:46 | Prop1 : Object | semmle.label | Prop1 : Object |
17841792
| J.cs:14:26:14:30 | field : Object | semmle.label | field : Object |
17851793
| J.cs:14:26:14:30 | field : Object | semmle.label | field : Object |
17861794
| J.cs:14:40:14:43 | prop : Object | semmle.label | prop : Object |
@@ -2022,6 +2030,10 @@ subpaths
20222030
| H.cs:147:25:147:38 | call to method Source<A> : A | H.cs:138:27:138:27 | o : A | H.cs:142:16:142:34 | access to field FieldB : A | H.cs:147:17:147:39 | call to method Through : A |
20232031
| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:153:32:153:32 | o : Object | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object |
20242032
| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:153:32:153:32 | o : Object | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object |
2033+
| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:6:40:6:44 | Prop1 : Object | J.cs:6:40:6:44 | Prop1 : Object | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object |
2034+
| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:6:40:6:44 | Prop1 : Object | J.cs:6:40:6:44 | Prop1 : Object | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object |
2035+
| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:8:42:8:46 | Prop1 : Object | J.cs:8:42:8:46 | Prop1 : Object | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object |
2036+
| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:8:42:8:46 | Prop1 : Object | J.cs:8:42:8:46 | Prop1 : Object | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object |
20252037
| J.cs:62:29:62:29 | access to local variable o : Object | J.cs:14:26:14:30 | field : Object | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object |
20262038
| J.cs:62:29:62:29 | access to local variable o : Object | J.cs:14:26:14:30 | field : Object | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object |
20272039
| J.cs:80:35:80:35 | access to local variable o : Object | J.cs:14:40:14:43 | prop : Object | J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object |

0 commit comments

Comments
 (0)