@@ -39,17 +39,15 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos)
39
39
}
40
40
41
41
/**
42
- * Gets the control flow node used for data flow purposes for the primary constructor
42
+ * Gets a control flow node used for data flow purposes for the primary constructor
43
43
* parameter access `pa`.
44
44
*/
45
- private ControlFlow:: Node getPrimaryConstructorParameterCfn ( ParameterAccess pa ) {
45
+ private ControlFlow:: Node getAPrimaryConstructorParameterCfn ( ParameterAccess pa ) {
46
46
pa .getTarget ( ) .getCallable ( ) instanceof PrimaryConstructor and
47
47
(
48
- pa instanceof ParameterRead and
49
- result = pa .getAControlFlowNode ( )
48
+ result = pa .( ParameterRead ) .getAControlFlowNode ( )
50
49
or
51
- pa instanceof ParameterWrite and
52
- exists ( AssignExpr ae | pa = ae .getLValue ( ) and result = ae .getAControlFlowNode ( ) )
50
+ pa = any ( AssignableDefinition def | result = def .getAControlFlowNode ( ) ) .getTargetAccess ( )
53
51
)
54
52
}
55
53
@@ -141,9 +139,10 @@ private module ThisFlow {
141
139
or
142
140
n .asExprAtNode ( cfn ) = any ( Expr e | e instanceof ThisAccess or e instanceof BaseAccess )
143
141
or
144
- exists ( InstanceParameterAccessNode pan | pan = n |
145
- pan .getUnderlyingControlFlowNode ( ) = cfn and pan .isPreUpdate ( )
146
- )
142
+ n =
143
+ any ( InstanceParameterAccessNode pan |
144
+ pan .getUnderlyingControlFlowNode ( ) = cfn and pan .isPreUpdate ( )
145
+ )
147
146
}
148
147
149
148
private predicate thisAccess ( Node n , BasicBlock bb , int i ) {
@@ -230,7 +229,7 @@ CIL::DataFlowNode asCilDataFlowNode(Node node) {
230
229
231
230
/** Provides predicates related to local data flow. */
232
231
module LocalFlow {
233
- private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
232
+ class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
234
233
LocalExprStepConfiguration ( ) { this = "LocalExprStepConfiguration" }
235
234
236
235
override predicate candidate (
@@ -955,7 +954,7 @@ private module Cached {
955
954
} or
956
955
TFlowInsensitiveFieldNode ( FieldOrProperty f ) { f .isFieldLike ( ) } or
957
956
TInstanceParameterAccessNode ( ControlFlow:: Node cfn , boolean isPostUpdate ) {
958
- exists ( ParameterAccess pa | cfn = getPrimaryConstructorParameterCfn ( pa ) |
957
+ exists ( ParameterAccess pa | cfn = getAPrimaryConstructorParameterCfn ( pa ) |
959
958
isPostUpdate = false
960
959
or
961
960
pa instanceof ParameterWrite and isPostUpdate = true
@@ -1795,6 +1794,19 @@ class FlowSummaryNode extends NodeImpl, TFlowSummaryNode {
1795
1794
1796
1795
/**
1797
1796
* A data-flow node used to model reading and writing of primary constructor parameters.
1797
+ * For example, in
1798
+ * ```csharp
1799
+ * public class C(object o)
1800
+ * {
1801
+ * public object GetParam() => o; // (1)
1802
+ *
1803
+ * public void SetParam(object value) => o = value; // (2)
1804
+ * }
1805
+ * ```
1806
+ * the first access to o (1) is modeled as this.o_backing_field and
1807
+ * the second access to o (2) is modeled as this.o_backing_field = value.
1808
+ * Both models need a pre-update this node, and the latter need an additional post-update this access,
1809
+ * all of which are represented by an InstanceParameterAccessNode node.
1798
1810
*/
1799
1811
class InstanceParameterAccessNode extends NodeImpl , TInstanceParameterAccessNode {
1800
1812
private ControlFlow:: Node cfn ;
@@ -1803,7 +1815,7 @@ class InstanceParameterAccessNode extends NodeImpl, TInstanceParameterAccessNode
1803
1815
1804
1816
InstanceParameterAccessNode ( ) {
1805
1817
this = TInstanceParameterAccessNode ( cfn , isPostUpdate ) and
1806
- exists ( ParameterAccess pa | cfn = getPrimaryConstructorParameterCfn ( pa ) and pa .getTarget ( ) = p )
1818
+ exists ( ParameterAccess pa | cfn = getAPrimaryConstructorParameterCfn ( pa ) and pa .getTarget ( ) = p )
1807
1819
}
1808
1820
1809
1821
override DataFlowCallable getEnclosingCallableImpl ( ) {
@@ -1836,6 +1848,16 @@ class InstanceParameterAccessNode extends NodeImpl, TInstanceParameterAccessNode
1836
1848
1837
1849
/**
1838
1850
* A data-flow node used to synthesize the body of a primary constructor.
1851
+ *
1852
+ * For example, in
1853
+ * ```csharp
1854
+ * public class C(object o) { }
1855
+ * ```
1856
+ * we synthesize the primary constructor for C as
1857
+ * ```csharp
1858
+ * public C(object o) => this.o_backing_field = o;
1859
+ * ```
1860
+ * The synthesized (pre/post-update) this access is represented an PrimaryConstructorThisAccessNode node.
1839
1861
*/
1840
1862
class PrimaryConstructorThisAccessNode extends NodeImpl , TPrimaryConstructorThisAccessNode {
1841
1863
private Parameter p ;
@@ -2000,13 +2022,25 @@ private PropertyContent getResultContent() {
2000
2022
result .getProperty ( ) = any ( SystemThreadingTasksTaskTClass c_ ) .getResultProperty ( )
2001
2023
}
2002
2024
2003
- private predicate primaryConstructorParameterStore ( Node node1 , ContentSet c , Node node2 ) {
2004
- exists ( AssignExpr ae , ParameterWrite pa , PrimaryConstructor constructor |
2005
- ae .getLValue ( ) = pa and
2006
- pa .getTarget ( ) = constructor .getAParameter ( ) and
2007
- node1 .asExpr ( ) = ae .getRValue ( ) and
2008
- node2 = TInstanceParameterAccessNode ( ae .getAControlFlowNode ( ) , true ) and
2009
- c .( PrimaryConstructorParameterContent ) .getParameter ( ) = pa .getTarget ( )
2025
+ private predicate primaryConstructorParameterStore (
2026
+ Node node1 , PrimaryConstructorParameterContent c , Node node2
2027
+ ) {
2028
+ exists ( ControlFlow:: Node cfn , Parameter p |
2029
+ node2 = TInstanceParameterAccessNode ( cfn , true ) and
2030
+ c .getParameter ( ) = p
2031
+ |
2032
+ // direct assignment
2033
+ exists ( LocalFlow:: LocalExprStepConfiguration conf , AssignableDefinition def |
2034
+ conf .hasDefPath ( _, node1 .( ExprNode ) .getControlFlowNode ( ) , def , cfn ) and
2035
+ p = def .getTarget ( )
2036
+ )
2037
+ or
2038
+ // indirect assignment (for example as an `out` argument)
2039
+ exists ( Ssa:: ExplicitDefinition def |
2040
+ def = node1 .( SsaDefinitionExtNode ) .getDefinitionExt ( ) and
2041
+ p = def .getSourceVariable ( ) .getAssignable ( ) and
2042
+ cfn = def .getControlFlowNode ( )
2043
+ )
2010
2044
)
2011
2045
}
2012
2046
@@ -2147,10 +2181,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
2147
2181
node2 .asExpr ( ) .( AwaitExpr ) .getExpr ( ) = node1 .asExpr ( ) and
2148
2182
c = getResultContent ( )
2149
2183
or
2150
- exists ( InstanceParameterAccessNode n | n = node1 |
2151
- n .getUnderlyingControlFlowNode ( ) = node2 .( ExprNode ) .getControlFlowNode ( ) and
2152
- n .getParameter ( ) = c .( PrimaryConstructorParameterContent ) .getParameter ( )
2153
- ) and
2184
+ node1 =
2185
+ any ( InstanceParameterAccessNode n |
2186
+ n .getUnderlyingControlFlowNode ( ) = node2 .( ExprNode ) .getControlFlowNode ( ) and
2187
+ n .getParameter ( ) = c .( PrimaryConstructorParameterContent ) .getParameter ( ) and
2188
+ n .isPreUpdate ( )
2189
+ ) and
2154
2190
node2 .asExpr ( ) instanceof ParameterRead
2155
2191
or
2156
2192
// node1 = (..., node2, ...)
@@ -2216,9 +2252,7 @@ predicate clearsContent(Node n, ContentSet c) {
2216
2252
not f .isRef ( )
2217
2253
)
2218
2254
or
2219
- exists ( Node n1 |
2220
- primaryConstructorParameterStore ( _, c , n1 ) and n = n1 .( PostUpdateNode ) .getPreUpdateNode ( )
2221
- )
2255
+ n = any ( PostUpdateNode n1 | primaryConstructorParameterStore ( _, c , n1 ) ) .getPreUpdateNode ( )
2222
2256
}
2223
2257
2224
2258
/**
@@ -2512,11 +2546,11 @@ module PostUpdateNodes {
2512
2546
private class InstanceParameterAccessPostUpdateNode extends PostUpdateNode ,
2513
2547
InstanceParameterAccessNode
2514
2548
{
2515
- private ControlFlow:: Node cfg ;
2549
+ private ControlFlow:: Node cfn ;
2516
2550
2517
- InstanceParameterAccessPostUpdateNode ( ) { this = TInstanceParameterAccessNode ( cfg , true ) }
2551
+ InstanceParameterAccessPostUpdateNode ( ) { this = TInstanceParameterAccessNode ( cfn , true ) }
2518
2552
2519
- override Node getPreUpdateNode ( ) { result = TInstanceParameterAccessNode ( cfg , false ) }
2553
+ override Node getPreUpdateNode ( ) { result = TInstanceParameterAccessNode ( cfn , false ) }
2520
2554
2521
2555
override string toStringImpl ( ) { result = "[post] this" }
2522
2556
}
0 commit comments